In [1]:
#pip install -r requirements.txt
In [2]:
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
import numpy as np
import seaborn as sns
from sklearn.decomposition import PCA
import geopandas as gpd
from prince import mca
import prince 
import requests
import io
import importlib
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import mean_squared_error, r2_score
from sklearn.impute import KNNImputer
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import Ridge, LinearRegression
import statsmodels.api as sm
from sklearn.ensemble import StackingRegressor, RandomForestRegressor
In [3]:
from scripts import clean_data as cld
from scripts import imputation as ipt
from scripts import data_analysis as dtn
from scripts import stats_desc as std
from scripts import regression as rgp
In [4]:
file_path ="https://minio.lab.sspcloud.fr/emile/Deep_seas/20177113_DS_D3.1-SEAS2-dataset-2022_rev1.csv"
df = pd.read_csv(file_path, sep=';', encoding='utf-8', low_memory=False, na_values=" ", decimal=',')
df.describe() 
Out[4]:
Respondent_Serial INTRO_CATI INTRO_CAWI SD_1 SD_2 QSD_2 SD_3 REG_CAT REG REG_quota ... cbsqf_alc c1cbsqf_alc cRSOD_1a SD_20_income_type SD_20 SD_20A SD_20B SD_20C sd_20month inc_mth
count 5.601400e+04 8810.0 47204.0 56014.000000 56014.000000 56014.000000 56014.000000 1516.000000 56014.000000 56014.000000 ... 55483.000000 55483.000000 47091.000000 47831.000000 2.974800e+04 16068.000000 1.270800e+04 4.245600e+04 4.245600e+04 4.245600e+04
mean 5.782639e+08 1.0 1.0 1.518781 41.056486 2.073624 16.854197 1.509235 297.832167 1668.286946 ... 777.543117 763.731402 158.253150 0.280508 4.147129e+05 1811.889283 6.781278e+04 3.108782e+05 4.172756e+04 1.965886e+04
std 1.637197e+09 0.0 0.0 0.501969 12.820770 0.872051 10.191840 0.982645 187.392295 997.947320 ... 1922.011090 1740.420721 134.101578 0.449252 1.872299e+06 3628.254842 1.784258e+05 1.578282e+06 1.432824e+05 8.073478e+04
min 1.900000e+01 1.0 1.0 1.000000 18.000000 1.000000 1.000000 1.000000 1.000000 101.000000 ... -1.000000 -1.000000 0.000000 0.000000 1.875000e+02 0.000000 1.875000e+02 1.875000e+02 1.250000e+02 1.250000e+01
25% 1.737850e+04 1.0 1.0 1.000000 30.000000 1.000000 8.000000 1.000000 114.000000 801.000000 ... 27.625000 27.625000 48.500000 0.000000 2.000000e+03 79.000000 1.950500e+03 2.000000e+03 1.500042e+03 6.944444e+02
50% 3.636400e+04 1.0 1.0 2.000000 41.000000 2.000000 16.000000 1.000000 325.000000 1606.000000 ... 195.000000 195.000000 107.600000 0.000000 4.500000e+03 169.000000 5.250000e+03 4.500500e+03 3.000500e+03 1.400000e+03
75% 5.647075e+04 1.0 1.0 2.000000 52.000000 3.000000 26.000000 2.000000 411.000000 2502.000000 ... 727.420000 727.420000 246.400000 1.000000 3.000000e+04 338.000000 3.499950e+04 3.250050e+04 1.125000e+04 4.500000e+03
max 7.600002e+09 1.0 1.0 3.000000 64.000000 3.000000 43.000000 4.000000 1477.000000 3409.000000 ... 63119.632500 18250.000000 400.000000 1.000000 1.656000e+07 9999.000000 1.500000e+06 1.656000e+07 1.380000e+06 1.380000e+06

8 rows × 186 columns

In [5]:
df.shape
Out[5]:
(56014, 191)

Sommaire¶

  • Partie I : Premier nettoyage
  • Partie II : Analyses et traitements
    • A. Statistiques descriptives
    • B. Imputation des données
    • C. Analyses factorielles (ACM & ACP)
  • Partie III : Modélisation
  • Annexes

Partie I : Premier nettoyage¶

Sélection des variables

In [6]:
variables = ["COUNTRY","SD_1", "SD_2", "SD_4","SD_6", "SD_7", 
             "SD_8","SD_9", "SD_10", "sd_20month" ,"social_class",
             "bsqf_alc", "f_1b", "RSOD_5a", "RSOD_5b", "RSOD_5c", "cbsqf_beer", "cbsqf_spir", "cbsqf_wine",
             "RSOD_5d", "RSOD_2b", "RSOD_7b", "CH_1", "WB_1", "WB_2", "WB_3"]
data = df[variables]

Explication de la sélection: Nous avons garder l'ensemble des variables qui faisaient sens du point de vue de la réponse à notre problématique. La plupart des variables non sélectionnées sont redondantes avec celles ici, (notamment des variables quantitatives qui avaient été recodées à partir des variables catégorielles que nous incluons ici). Toutes les variables recueillant l'opinion des interrogés ont été exclues pour leur difficulté potentielle à être traiter, par exemple: AP_9: Printed warnings about alcohol-related harm should be displayed on alcohol packaging ? Strongly agree, somewhat agree,...

In [7]:
data.dtypes
Out[7]:
COUNTRY           int64
SD_1              int64
SD_2              int64
SD_4              int64
SD_6              int64
SD_7            float64
SD_8              int64
SD_9              int64
SD_10             int64
sd_20month      float64
social_class      int64
bsqf_alc        float64
f_1b              int64
RSOD_5a         float64
RSOD_5b         float64
RSOD_5c         float64
cbsqf_beer      float64
cbsqf_spir      float64
cbsqf_wine      float64
RSOD_5d         float64
RSOD_2b         float64
RSOD_7b         float64
CH_1              int64
WB_1              int64
WB_2              int64
WB_3              int64
dtype: object

Nettoyage de la base

In [8]:
#Les pays de la base sont codés de 10 à 43, on les associe à leur nom via le dictionnaire country_mapping de clean_data
if pd.api.types.is_numeric_dtype(data['COUNTRY']):
    data['COUNTRY'] = data['COUNTRY'].map(cld.country_mapping)
else:
    print("Le mapping a déjà été effectué, on ne fait rien.") #Pour éviter de remplacer par NA si on exécute ce code 2 fois par erreur
C:\Users\Utilisateur\AppData\Local\Temp\ipykernel_22520\1535886202.py:3: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
  data['COUNTRY'] = data['COUNTRY'].map(cld.country_mapping)

Le questionnaire de Deepseas précise que le salaire mensuel sd_20month a été fourni en monnaie locale par les répondants mais le code book ne précise pas si la variable a été remise dans la même unité monétaire ou non. Regardons la distribution des revenus par pays ci-dessous:

In [9]:
cld.barplot_bycntry(data)
No description has been provided for this image

La variable sd_20month du salaire mensuel est restée en monnaie local puisque les pays hors zone euro qui ont presque tous une monnaie plus faible que l'euro se retrouvent à avoir les salaires mensuels les plus élevés, alors que ce ne sont pas nécessairement ceux où le niveau de vie est le plus élevé. On notera que les valeurs manquent pour la Slovénie dû au fait que le questionnaire slovène n'a pas précisé si les répondants devaient donner leur salaire mensuel ou annuel, les sondeurs ont donc supprimer les données de salaire pour ce pays.

Les entretients pour construire cette base de données ayant été menés en 2019 et 2020, nous choisissons de convertir tous les salaires en euros selon les valeurs publiées au journal officiel de l'Union Européenne pour le 2 janvier 2020. Cette date qui précède la crise Covid peut permettre d'éviter des erreurs d'interprétation des niveaux de vie, la crise Covid ayant fait significativement fluctuer les taux de change, faisant notamment s'apprécier l'euro par rapport à certaines monnaies début 2020 (couronne tchèque, islandaise, etc.).

In [10]:
# On crée une variable avec les taux de changes de 2020 
data['EXCHANGE_RATE_TO_EUR'] = data['COUNTRY'].map(cld.conversion_rates)

# On convertit la variable 'sd_20month'
data['sd_20month_EUR_2020'] = data['sd_20month'] * data['EXCHANGE_RATE_TO_EUR']
C:\Users\Utilisateur\AppData\Local\Temp\ipykernel_22520\1698145111.py:2: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
  data['EXCHANGE_RATE_TO_EUR'] = data['COUNTRY'].map(cld.conversion_rates)
C:\Users\Utilisateur\AppData\Local\Temp\ipykernel_22520\1698145111.py:5: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
  data['sd_20month_EUR_2020'] = data['sd_20month'] * data['EXCHANGE_RATE_TO_EUR']
In [11]:
# Barplot des salaires mensuels moyens convertis en €
cld.barplot_bycntry(data, colonne_y='sd_20month_EUR_2020',y_name= "revenu mensuel moyen par pays (en €)")
No description has been provided for this image

On remarque que cette distribution des revenus n'est pas toujours cohérente avec la réalité des distributions moyennes de revenus entre les pays européens. Par exemple, le revenu moyen déclaré par les italiens interrogés est supérieur à celui des irlandais interrogés, ce qui n'est pas vrai dans la population totale. Cela témoigne soit d'un biais déclaratif plus élevé dans certains pays que d'autres, soit d'un biais de sélection du fait que les personnes interrogées dans certains pays (en Italie par exemple) font partie d'une partie plus favorisée économiquement de la population de leur pays que les individus interrogés dans d'autres pays (par exemple l'Irlande). Le cas échéant, cela signifie que les personnes interrogées ne sont pas équitablement répartis dans la distribution des revenus, dans certains pays du moins (ce que Kilian et Al. pointent du doigt dans leur papier "The socioeconomic profile of alcohol use in Europe: Findings from a cross-sectional survey of 33 European countries" qui analyse Deepseas du point de vue européen).

NB: Les salaires extrêmement hauts de la Slovénie sont dû à un oubli de la part des sondeurs de préciser si le salaire était mensuel ou annuel dans les questions posées aux slovènes. On ne pourra donc pas utiliser ce pays pour notre étude.

On décide de créer également une nouvelle variable de salaire mensuel en euros PPA pour pouvoir comparer les pays selon leur pouvoir d'achat. On liste ci-après les taux PPA donnés par Eurostat et la Banque Mondiale qui correspondent au Taux de change/ Indice des prix.

In [12]:
# Création d'un variable Valeurs brutes de parité (PPA) et conversion des salaires en euros PPA
data['PPA'] = data['COUNTRY'].map(cld.ppa_brut)
data['sd_20month_EUR_2020_PPA']= data['sd_20month'] / data['PPA']
C:\Users\Utilisateur\AppData\Local\Temp\ipykernel_22520\581596296.py:2: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
  data['PPA'] = data['COUNTRY'].map(cld.ppa_brut)
C:\Users\Utilisateur\AppData\Local\Temp\ipykernel_22520\581596296.py:3: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
  data['sd_20month_EUR_2020_PPA']= data['sd_20month'] / data['PPA']

Premier traitement des valeurs manquantes

In [13]:
# Affiche le tableau des données manquantes par variable (en %)
stats_na = cld.tableau_na(data)
stats_na
Out[13]:
TABLEAU RÉCAPITULATIF DES DONNÉES MANQUANTES
Source : The Standard European Alcohol Survey – Wave 2 | Champ : 33 pays européens
Variable Taux de manquants
COUNTRY 0.00%
SD_1 0.00%
SD_2 0.00%
SD_4 0.00%
SD_6 0.00%
SD_7 21.22%
SD_8 0.00%
SD_9 0.00%
SD_10 0.00%
sd_20month 24.20%
social_class 0.00%
bsqf_alc 0.95%
f_1b 0.00%
RSOD_5a 45.65%
RSOD_5b 45.65%
RSOD_5c 45.65%
cbsqf_beer 0.00%
cbsqf_spir 0.00%
cbsqf_wine 0.00%
RSOD_5d 45.65%
RSOD_2b 26.87%
RSOD_7b 50.24%
CH_1 0.00%
WB_1 0.00%
WB_2 0.00%
WB_3 0.00%
EXCHANGE_RATE_TO_EUR 0.00%
sd_20month_EUR_2020 24.20%
PPA 0.00%
sd_20month_EUR_2020_PPA 24.20%
In [14]:
#version plus visuelle du tableau précédent
cld.visu_na(data)
No description has been provided for this image

Les variables présentant des valeurs manquantes dans des proportions potentiellement problématiques sont:

  • SD_7: le nombre de mineur dans le foyer de l'individu (21% de NA)
  • SD_20month : le revenu du ménage par mois (24% de NA)
  • Demo_Empl: si temps partiel, temps plein ou autre (31% de NA)
  • Les RSOD_5(a à d): les lieux de consommation d'alcool (46% de NA)
  • RSOD_2b : Fréquence 4/6+ verres en nombre de jours par an (46% de NA) ;
  • RSOD_7b : Fréquence 8/12+ verres en nombre de jours par an (50% de NA)

Nous les traiterons une par une par la suite.

Traitement de bsqf_alc la consommation d'alcool pur par an et par individu en cl

In [15]:
#pourcentages de valeurs manquantes pour la quantité d'alcool consommée dans les 12 derniers mois (en cl)
cld.tableau_na_pays(data, "bsqf_alc")
Out[15]:
TAUX DE VALEURS MANQUANTES PAR PAYS (bsqf_alc)
Source : SEAS-2 | Champ : 33 pays européens
  bsqf_alc
COUNTRY  
Austria 0.018094
Belgium 0.009309
BosniaHerzegovina 0.004667
Bulgaria 0.002329
Catalunya 0.011873
Croatia 0.002663
Cyprus 0.008667
Czech Republic 0.006662
Denmark 0.012018
Estonia 0.005563
Finland 0.000000
France 0.017564
Germany 0.023179
Greece 0.001314
Hungary 0.012942
Iceland 0.036667
Ireland 0.006662
Italy 0.003989
Latvia 0.003989
Lithuania 0.009229
Luxembourg 0.004648
Malta 0.029333
Moldova 0.001333
Netherlands 0.013298
Norway 0.014000
Poland 0.000641
Portugal 0.004660
Romania 0.005319
Serbia 0.007989
Slovakia 0.007973
Slovenia 0.014637
Spain 0.006647
Sweden 0.007371
United Kingdom 0.005312
In [16]:
#Peu de valeurs manquantes dans la consommation d'alcool en cl d'alcool pur bsqf_alc (moins de 2% sauf Islande, Allemagne et Malte moins de 3.7%) 
# donc on peut supprimer les individus qui présentent des valeurs manquantes pour cette variable sans créer de biais de sélection.

data= data.dropna(subset=['bsqf_alc'])
sum(data['bsqf_alc'].isna())
Out[16]:
0

Les variables RSOD_5(a à d)

In [17]:
variables = ['RSOD_5a', 'RSOD_5b', 'RSOD_5c', 'RSOD_5d']

#Pourcentage d'observations où TOUTES les variables RSOD_5(a à d) sont manquantes
pourcentage_observations_manquantes_communes = data[variables].isna().all(axis=1).mean()

print(f"Nombre d'observations où toutes les variables sont manquantes : {pourcentage_observations_manquantes_communes}")
Nombre d'observations où toutes les variables sont manquantes : 0.45266117549519674

Les valeurs manquantes des RSOD_5(a à d) sont les mêmes, donc quand on ne connaît pas la récurrence de consommation d'alcool dans un lieu, on ne la connaît pour aucun. Ces variables présentent un très grand pourcentage de valeurs manquantes (46%) et ne sont pas évoqués dans la littérature que nous avons étudié comme déterminant d'un profil de consommateur d'alcool, nous décidons de ne pas les compléter et d'étudier leur rôle seulement au travers de quelques statistiques descriptives par pays.

Puisque ces variables ne sont pas complémentaires en termes d'individus répondants, qu'il y a plus de 45% de valeurs manquantes et que nous ne les avons trouvé comme typiques de certains consommateurs d'alcool dans aucune étude que nous avons lues, nous décidons de ne pas les étudier et de les retirer de la base pour le traitement.

In [18]:
# Identification et suppression des colonnes RSOD_5(a à d)
cdrop = ["RSOD_5a", "RSOD_5b", "RSOD_5c", "RSOD_5d"]
data = data.drop(columns=cdrop)

print(f"Colonnes supprimées : {cdrop}")
Colonnes supprimées : ['RSOD_5a', 'RSOD_5b', 'RSOD_5c', 'RSOD_5d']

Traitement de RSOD_2b et RSOD_7b

Variables catégorielles, respectivement la fréquence de consommation d'alcool supérieure à 4/6 verres et supérieure 8/12 verres.

In [19]:
#regardons si, de façon cohérente, les valeurs manquantes de RSOD_2b sont incluses dans celles de RSOD_7b qui en a davantage

print(f"NA uniquement dans 2b: {(data['RSOD_2b'].isna() & data['RSOD_7b'].notna()).sum()}")
print(f"NA uniquement dans 7b: {(data['RSOD_2b'].notna() & data['RSOD_7b'].isna()).sum()}")
NA uniquement dans 2b: 0
NA uniquement dans 7b: 13000

Donc si des valeurs sont manquantes dans RSOD_2b elles le sont bien aussi dans RSOD_7b, donc les gens qui n'ont pas répondu à leur fréquence de consommation d'alcool de 4/6+ verres n'ont pas non plus répondu à celle de 8/12+ verres .

Les RSOD_2b/7b sont codées comme suit (d'après le code book):

Frequency of drinking 4/6+ (resp. 8/12+ ) drinks

  • 1 = Every day
  • 2 = 5-6 days a week
  • 3 = 3-4 days a week
  • 4 = 1 - 2 days a week
  • 5 = 2 - 3 days a month
  • 6 = One day in a month
  • 7 = 6 - 11 days a year
  • 8 = 2 - 5 days a year
  • 9 = a single day in the past 12 months
  • 10 = I did not drink in the past 12 months

Comme RSOD_7b a 50% de valeurs manquantes, on décide de l'abandonner pour ne garder que RSOD_2b qui en a 27%. On retiendra que, même si RSOD_7b est inclus dans RSOD_2b, on perd tout de même un peu d'information sur les alcoolisations ponctuelles importantes.

In [20]:
# Identification et suppression de la colonne RSOD_7b
cdrop = ["RSOD_7b"]
data = data.drop(columns=cdrop)
In [21]:
#Problème: On a remarqué en ouvrant la base sur excel (ça n'est donc pas une erreur d'interprétation des séparateurs) qu'il y a à la fois des 0 et des NA pour ces variables
#Alors que ce sont des catégorielles sans catégories 0 D'APRES LE CODEBOOK
#Comptons le nombre de 0 et de valeurs manquantes pour RSOD_2b
print(f"nombre de d'individus ayant RSOD_2b = 0: {data.loc[data['RSOD_2b']==0,'RSOD_2b'].count()}",
f", nombre de valeurs manquantes pour RSOD_2b: {data['RSOD_2b'].isna().sum()}")
nombre de d'individus ayant RSOD_2b = 0: 5286 , nombre de valeurs manquantes pour RSOD_2b: 14650
In [22]:
# Le codebook pourrait-il se tromper ?
# Essayons de voir combien d'individus correspondent à chaque code catégoriel de 1 à 10 possible:
print(data['RSOD_2b'].value_counts(dropna=False).sort_index())
RSOD_2b
0.0     5286
1.0      939
2.0      963
3.0     2597
4.0     4244
5.0     5590
6.0     3055
7.0     4499
8.0     6383
9.0     7277
NaN    14650
Name: count, dtype: int64

Il n'y a pas d'observation codée 10, il est cohérent de penser que le code book contient une erreur et que c'est le code 0 qui correspond à "I did not drink in the past 12 months [4/6+ drinks]" et non pas le code 10. Pour le vérifier, on va essayer de voir si les individus codés 0 sont bien ceux codés 10 dans le code book et si les codes des autres catégories sont restés inchangés ou non. Pour cela, on utilise la variable de fréquence de consommation d'alcool f_1b qui n'est pas un excellent proxy de RSOD_2b la fréquence de consommation de plus de 4/6 verres mais qui est le meilleur que nous ayons.

Rappel:codage de f_1b

generic frequency of drinking

  • 1 = Every day
  • 2 = 5-6 days a week
  • 3 = 3-4 days a week
  • 4 = 1 - 2 days a week
  • 5 = 2 - 3 days a month
  • 6 = One day in a month
  • 7 = 6 - 11 days a year
  • 8 = 2 - 5 days a year
  • 9 = a single day in the past 12 months
  • 10 = I did not drink but I drank earlier
  • 11 = I never drank in my life
In [23]:
#On regarde quelle est la distribution de la variable f_1b
print(data['f_1b'].value_counts(dropna=False).sort_index())
f_1b
1      3703
2      4461
3      5614
4     13722
5      8881
6      3581
7      4341
8      4583
9      1311
10     2399
11     2887
Name: count, dtype: int64
In [24]:
print(f"Le nombre d'individus où RSOD_2b=0 et f_1b=10 ou 11 est : {data.loc[(data['RSOD_2b']==0) & ((data['f_1b'] == 10) |  (data['f_1b'] == 11)), 'RSOD_2b'].count()}",
f", Le nombre d'individus ou RSOD_2b=0 est {data['RSOD_2b'].value_counts(dropna=False)[0]}")
Le nombre d'individus où RSOD_2b=0 et f_1b=10 ou 11 est : 5286 , Le nombre d'individus ou RSOD_2b=0 est 5286

Les individus ayant n'ayant jamais consommé d'alcool dans les 12 derniers mois ou durant toute leur vie (catégorie 10 et 11 de f_1b) sont biens les mêmes qui ont RSOD_2b=0. Le code 10 est bien devenu 0.

Pour vérifier la concordance des codes 1 à 9 avec les labels du codebook, on crée une table de contingence entre RSOD_2b et f_1b.

In [25]:
# Table de contingence de la fréquance générique de consommation d'alcool 
# et de la fréquence de + de 4 verres
#NB: On est obligé de remplacer les RSOD_2b manquants par 0, ce qui est une limite à notre analyse
cld.trace_table_contingence(data)
No description has been provided for this image

Exemple d'interprétation: Tous les individus qui n'ont jamais consommé d'alcool dans leur vie ou durant les 12 derniers mois (f1_b=10 (2399 individus) ou 11(2887 individus)) n'ont jamais consommé plus de 4/6 verres d'alcool dans les 12 derniers mois. On valide de nouveau notre labelisation 0 = I did not drink in the past 12 month.

Puisque les codes 1 à 9 ont les mêmes labels pour les variables RSOD_2b et f_1b et que la diagonale de la table de contingence contient globalement dans les effectifs les plus élevés, en supposant une corrélation significative entre ces deux variables, on peut conclure que l'ordre pas été décallé par rapport au codebook (hormis 10 évidemment). Si les codes avaient été décalés (par exemple si le 1 était devenu 2), nous verrions un décalage systématique de la diagonale, ce qui n'est pas le cas ici.

NB: On notera qu'on a remplacé les RSOD_2b manquants par 0 pour construire cette table ce qui est une légère limite à cette analyse.

Cela nous permet de confirmer assez sûrement l'hypothèse suivante: La bonne distribution de RSOD_2b est: Frequency of drinking 4/6+ (resp. 8/12+ ) drinks

  • 0 = I did not drink in the past 12 months
  • 1 = Every day
  • 2 = 5-6 days a week
  • 3 = 3-4 days a week
  • 4 = 1 - 2 days a week
  • 5 = 2 - 3 days a month
  • 6 = One day in a month
  • 7 = 6 - 11 days a year
  • 8 = 2 - 5 days a year
  • 9 = a single day in the past 12 months

On peut par ailleurs utiliser cette table pour faire quelques commentaires sur la distribution statistique de RSOD_2b:

  1. Dans nos deux échelles, plus le chiffre est petit, plus la fréquence est élevée (1 = tous les jours, 9 = 1 jour par an).

Or, on voit qu'il n'y a quasiment aucune observation dans la zone "sud-ouest" du tableau.

Ce qui est bon car cela signifie que personne n'a une fréquence de "forte consommation" (RSOD_2b) supérieure à sa fréquence de "consommation générale" (f_1b).Par exemple, personne n'est codé f_1b =4 (boit 1-2 fois/semaine) tout en étant RSOD_2b = 1 (boit 4/6+ verres tous les jours). C'est logiquement impossible, et la base respecte cela.

  1. La distribution des "Binge Drinkers" (def: alcoolisation ponctuelle importante dans un temps très court, avec recherche d’ivresse)

Les points les plus denses pour les codes 1 à 9 se situent sur la diagonale ou légèrement à droite de celle-ci.

Exemple sur la ligne 4 (f_1b) : Le pic est au croisement avec la colonne 4 de RSOD_2b. Cela indique que les gens qui boivent 1 à 2 jours par semaine boivent souvent 4/6+ verres à chaque fois qu'ils consomment.

  1. Les lignes 4 et 5 sont plus foncées:

Cela signifie que les consommateurs "intermédiaires" en terme de fréquence de consommation (entre 2 jours par semaine et deux jours par mois), consomment des quantités importantes d'alcool moins réguliérement que leur fréquence générale de consommation. Comme les effectifs sont relativement proches pour ces lignes, ces consommateurs intermédiaires ont des profils très hétérogènes dans leur attitude de "binge drinking", presque autant la pratiquent 2 à 3 fois par mois (2166 individus) que une fois par an (1895).

In [26]:
# On compte les NA
print(f"Nombre de NA dans RSOD_2b : {data['RSOD_2b'].isna().sum()}")
Nombre de NA dans RSOD_2b : 14650

Avant de traiter ces valeurs manquantes, nous regardons si les répondants diffèrent selon s'ils ont répondu ou non à la question sur leur consommation excessive d'alcool.

In [27]:
#création d'une variable valant 1 si RSOD_2b est manquante et 0 sinon
data['RSOD_2bisna'] = data['RSOD_2b'].isna().astype(int)
In [28]:
# Diagrammes circulaires des parts de valeurs manquantes pour RSOD_2b selon le genre

labels_sexe = {1.0: "Homme", 2.0: "Femme", 3.0: "Autre"}
source_sexe = "Source : SEAS-2 | Champ : 33 pays européens\nLecture : 25.9% des hommes interrogés n'ont pas répondu à la question 'A quelle fréquence buvez-vous plus de 4 verres d'alcool?'"

cld.trace_camemberts_na(data, var_na='RSOD_2bisna', var_groupe='SD_1', 
                         dict_labels=labels_sexe, 
                         titre_general="Répartition des valeurs manquantes (RSOD_2b) par Genre",
                         source_texte=source_sexe)
No description has been provided for this image

On remarque que les personnes ne se déclarant ni homme, ni femme répondent presque deux fois moins à la question sur leur consommation ponctuelle excessive d'alcool. Les interrogés se déclarant comme homme ou femmme répondent dans les mêmes proportion (~26%). On peut l'interpréter de deux manières:

  • soit certaines personnes sont réticentes à dévoiler toute sorte d'information, que ce soit le genre ou la consommation excessive d'alcool;
  • soit les personnes qui négligent le questionnaire négligent en particulier ces deux questions;
  • soit les personnes ne s'identifiant à aucun genre sont plus réticent à dévoiler leur consommation d'alcool.

DANGEREUX REVOIR

In [29]:
# source et lecture spécifique
lecture = ("Source : SEAS-2 | Champ : 33 pays européens\n"
           "Lecture :  Parmi les 10% des interrogés qui déclarent consommer le moins d'alcool (D1),\n"
    "seuls 4.8% ne répondent pas à la question 'A quelle fréquence buvez-vous plus de 4 verres d'alcool?'")

# Crée barres empilées avec le % de répondants à la fréquence de consommation excessive d'alcool (4 verres et +) par déciles de la distribution de consommation d'alcool 
cld.trace_barplot_na(data, var_quanti='bsqf_alc', var_na='RSOD_2bisna', source_texte=lecture)
No description has been provided for this image
In [30]:
seuils = data['bsqf_alc'].quantile([0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9])
print(seuils)
0.1       1.375
0.2      18.910
0.3      53.000
0.4     117.900
0.5     216.750
0.6     370.510
0.7     612.000
0.8    1061.150
0.9    2206.948
Name: bsqf_alc, dtype: float64

Relation en "U inversé" pour la non-réponse: On observe que la part des "Non-répondants" (en bleu) n'est pas distribuée de manière uniforme :

Aux extrémités (D1 et D10) : Le taux de réponse est maximal. Les personnes qui consomment pas ou très peu d'alcool ou beaucoup répondent presque toutes à la question RSOD_2b.

On observe un pic de non-réponse, culminant à 75.1% pour le décile 2 et 46.7% pour le décile 3.

Proposition d'interprétation: (observation difficilement interprétable)

L'hypothèse explicative pourrait être que les gros consommateurs répondent plus facilement car ils identifient clairement ce comportement dans leur quotidien et sont donc plus enclins à déclarer une fréquence, même si elle est élevée. Et inversement pour les faibles consommateurs. Pour les très faibles consommateurs du 1er décile, ils consomment moins de 1.375 cl d'alcool par an, et savent donc qu'ils n'ont jamais consommé plus de 4 verres soit 40/7.89= 5 cl d'alcool.

In [31]:
labels_social = {1.0: "Blue collar", 2.0: "White collar", 3.0: "Manager", 
                 4.0: "Business person", 5.0: "Other", 9.0: "No response"}
source_social = (
    "Source : The Standard European Alcohol Survey – Wave 2\n"
    "Champ : 33 pays européens\n"
    "Lecture : 23% des interrogés déclarant occuper un emploi d'ouvrier/employé (col bleu) ne répondent pas à la question\n"
    "'A quelle fréquence buvez-vous plus de 4 verres d'alcool?'"
)
cld.trace_camemberts_na(data, var_na='RSOD_2bisna', var_groupe='social_class', 
                         dict_labels=labels_social, 
                         titre_general="Répartition des NA (RSOD_2b) par Classe Sociale",
                         source_texte=source_social)
No description has been provided for this image

On observe pas de différence significative dans les taux de non réponse pour RSOD_2b entre les différentes classes sociales. Une séquence de diagrammes circulaires l'illustre en annexe

In [32]:
# Ratio de valeurs manquantes par pays pour RSOD_2b
cld.tableau_na_pays(data, var="RSOD_2b")
Out[32]:
TAUX DE VALEURS MANQUANTES PAR PAYS (RSOD_2b)
Source : SEAS-2 | Champ : 33 pays européens
  RSOD_2b
COUNTRY  
Austria 0.264232
Belgium 0.212081
BosniaHerzegovina 0.463496
Bulgaria 0.111741
Catalunya 0.333111
Croatia 0.172897
Cyprus 0.711500
Czech Republic 0.153588
Denmark 0.288732
Estonia 0.151515
Finland 0.114438
France 0.414779
Germany 0.266441
Greece 0.165789
Hungary 0.289460
Iceland 0.368858
Ireland 0.136821
Italy 0.279039
Latvia 0.160214
Lithuania 0.220892
Luxembourg 0.464977
Malta 0.281593
Moldova 0.461282
Netherlands 0.285714
Norway 0.207573
Poland 0.112251
Portugal 0.328428
Romania 0.278075
Serbia 0.231544
Slovakia 0.198928
Slovenia 0.320729
Spain 0.294404
Sweden 0.193069
United Kingdom 0.230307

Le pourcentage de valeurs manquantes pour RSOD_2b varie aussi selon les pays allant de 0.11 pour la Bulgarie à 0.71 pour Chypre. On notera que ces pays ont respectivement la plus forte et la plus faible consommation moyenne d'alcool en cl parmi les pays de la base. De manière générale, les pays qui consomment en moyenne le moins d'alcool ont aussi les plus hauts taux de non réponses et inversement.

Les personnes ayant RSOD_2b en valeur manquante ont donc bien un profil particulier, notamment en ce qui concerne leur consommation d'alcool. Les personnes qui consomment le moins d'alcool, répondent moins souvent à leur fréquence de consommation excessive. Ces valeurs manquantes engendrent donc un biais de sélection qu'il faudra prendre en compte dans nos interprétation. Ce qui est rassurrant pour notre analyse par pays, c'est que les pays qui consomment en moyenne le moins d'alcool ont bien aussi les plus hauts taux de non réponses et inversement. Si la baisse de la consommation de toute la population est proportionnelle à la hausse du nombre de valeur manquante, on peut se dire que le biais engendré sera environ le même peu importe les pays, ce qui pourrait ne pas trop impacter la comparaison entre pays.

RSOD_2b - premiers traitement des valeurs manquantes

Pour gérer les valeurs manquantes de RSOD_2b, on décide d'utiliser les variables de fréquence de consommation d'alcool par an (rf_1b) et de quantité consommée en gramme d'alcool pur (bsqf_alc). Nous choisirons, comme les auteurs de la base le font dans leur conversions (cf. document "database guidelines" du github), de considérer qu'un verre d'alcool représente en moyenne 10 grammes d'alcool pur.

Algorithme naïf :

  1. On prend toutes les valeurs manquantes de RSOD_2b
  2. diviser bsqf par masse volumique de l'alcool 0.789 kg/L
  3. diviser cela par rf_1b (recodé en quantitive en jour de consommation d'alcool par an)= on obtient la consommation moyenne en gramme d'alcool par jour où on a consommé de l'alcool sur l'année passée
  4. si celle-ci est inférieure à 40g (c'est à dire 4 verres), on met RSOD_2b = 0, sinon on met RSOD_2b= même valeur que fréquence générique rf1_b

On ne peut pas appliquer cet algorithme naïf qui réduirait la variance de consommation d'alcool des individus ayant une valeur manquante pour RSOD_2b à zéro. Cependant, il y a deux cas de valeurs manquantes que l'on peut traiter facilement:

  1. les individus qui ont consommé moins de 40g (soit 4 verres) d'alcool pur dans l'année et auxquels on peut attribuer RSOD_2b=0;
  2. les individus qui ont consommé une seule fois par an plus de 40g d'alcool pur auxquels on peut attribuer RSOD_2b=9;

Pour le reste des valeurs manquantes sur cette variable, nous utiliserons la méthode d'imputation par "le plus proche voisin" après avoir sélectionner nos pays d'intérêt.

In [33]:
# 1
# On regarde le nombre d'individu qui consomme moins de 40g par an soit 4 verre d'alcool selon notre critère de conversion, 
# ceux là sont forcément dans la catégorie 0 de RSOD_2b

print(len(data.loc[data['RSOD_2b'].isna() & (data['bsqf_alc'] < 40/7.89)])) # On divise par la masse volumique de l'alcool pur en gramme/cl car bsqf_alc est en cl

#On remplace ces valeurs manquantes de RSOD_2b par 0 
data['RSOD_2b'] =data['RSOD_2b'].copy()
data.loc[data['RSOD_2b'].isna() & (data['bsqf_alc'] < 40/7.89),'RSOD_2b'] = 0
1591
In [34]:
#2
print(len(data.loc[data['RSOD_2b'].isna() & (data['bsqf_alc'] > 40/7.89) & (data['f_1b']==9)]))
data.loc[data['RSOD_2b'].isna() & (data['bsqf_alc'] > 40/7.89) & (data['f_1b']==9),'RSOD_2b'] = 9
146

SD_7 et Demo_Empl

Les valeurs manquantes des variables SD_7 (nombre d'enfant mineur dans le ménage) et Demo_Empl (Temps plein, temps partiel ou autre) seront traités par pays si des relations intéressantes sont trouvées sur les statistiques descriptives nationales concernant celles-ci. Elles ne sont pas évoquées comme majeures dans la détermination de la consommation d'alcool par la littérature.

In [35]:
#distribution du nombre de mineur par foyer
cld.afficher_tableau_distribution(data, "Environ 24 000 interrogés, soit 55.2% des interrogés vivent dans un foyer où n'habite aucun mineur.")
Source : SEAS-2 | Champ : France | Lecture : Environ 24 000 interrogés, soit 55.2% des interrogés vivent dans un foyer où n'habite aucun mineur.
  Effectif Pourcentage (%)
SD_7    
0.000000 24130 55.190000
1.000000 10661 24.380000
2.000000 7035 16.090000
3.000000 1495 3.420000
4.000000 276 0.630000
5.000000 87 0.200000
6.000000 21 0.050000
7.000000 7 0.020000
8.000000 2 0.000000
9.000000 1 0.000000
10.000000 1 0.000000
11.000000 2 0.000000
12.000000 2 0.000000
13.000000 2 0.000000
In [36]:
# Barplot de la consommation d'alcool moyenne annuel par individus ayant le même nombre de mineur dans leur foyer
cld.tracer_barplot_vsbscqf(data, "Un répondant vivant dans un foyer sans mineur consomme en moyenne environ 10L (1000cl) d'alcool pur par an.", var_x="SD_7", var_y="bsqf_alc")
No description has been provided for this image

On remarque qu'il y a une assez forte variation de la consommation d'alcool selon le nombre de mineur dans le foyer. Les personnes qui ont un mineur dans leur foyer (y compris eux), parmi les répondants, consomment en moyenne plus d'une fois et demi plus que ceux qui n'ont pas de mineur dans leur foyer. On remarquera qu'il n'est pas pertinent de prendre en compte les individus déclarant avoir plus de 6 enfants dans leurs foyers, qui sont trop peu nombreux et contiennent des outliers en termes de consommateurs d'alcool. Néanmoins on retiendra qu'il est intéressant de traiter les valeurs manquantes pour cette variable pour l'étudier, ce que l'on fera par la suite. Encore une fois, une partie de l'effet constaté peut être dû à un biais de sélection sur les répondants/non répondants à SD_7, mais on suppose que cela ne crée pas tout l'effet.

sd_20month - salaire mensuel

Il est important de traiter le cas de la variable salaire sd_20month, car les facteurs économiques jouent, selon la littérature, un rôle important dans la consommation d'alcool (les plus favorisés auraient notamment tendance à consommer plus régulièrement de l'alcool mais en moins grande quantité). Le salaire étant la seule variable quantitative indiquant la situation économique des individus que nous ayont, nous devons traiter le problème de valeur manquante sur cette variable.

In [37]:
missing_by_country = data.groupby('COUNTRY').apply(lambda x: x.isna().mean()) #on le remet car data a changé 
missing_by_country['sd_20month']
observation_count = data.groupby('COUNTRY').size()

# Ajouter le nombre d'observation par pays
missing_by_country['Observation_Count'] = observation_count

print(missing_by_country.loc[:, ["sd_20month", "Observation_Count"]])
                   sd_20month  Observation_Count
COUNTRY                                         
Austria              0.262257               3039
Belgium              0.251678               1490
BosniaHerzegovina    0.146015               1493
Bulgaria             0.208139               2998
Catalunya            0.295728               1498
Croatia              0.223632               1498
Cyprus               0.156691               1487
Czech Republic       0.168343               1491
Denmark              0.245198               1562
Estonia              0.524476               2145
Finland              0.166334               1503
France               0.128725               1678
Germany              0.153220               1475
Greece               0.230263               1520
Hungary              0.174987               1983
Iceland              0.094810               1445
Ireland              0.215962               1491
Italy                0.210280               1498
Latvia               0.377837               1498
Lithuania            0.226880               1503
Luxembourg           0.252168               1499
Malta                0.188187               1456
Moldova              0.280374               1498
Netherlands          0.250674               1484
Norway               0.267748               1479
Poland               0.134060               1559
Portugal             0.199331               1495
Romania              0.120989               1496
Serbia               0.215436               1490
Slovakia             0.248493               1493
Slovenia             1.000000               1481
Spain                0.149635               1644
Sweden               0.194926               1616
United Kingdom       0.181575               1498
C:\Users\Utilisateur\AppData\Local\Temp\ipykernel_22520\1508566044.py:1: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  missing_by_country = data.groupby('COUNTRY').apply(lambda x: x.isna().mean()) #on le remet car data a changé
In [38]:
# 1.Voir combien de personnes ont été interrogées par pays
display(cld.tableau_effectifs_pays(data))

# 2. Voir le taux de non-réponse au revenu (sd_20month)
display(cld.tableau_na_pays(data, var="sd_20month"))
RÉPARTITION DU NOMBRE DE RÉPONDANTS PAR PAYS
Source : The Standard European Alcohol Survey – Wave 2| Champ : 33 pays européens
  Nombre d'observations
COUNTRY  
Austria 3,039
Bulgaria 2,998
Estonia 2,145
Hungary 1,983
France 1,678
Spain 1,644
Sweden 1,616
Denmark 1,562
Poland 1,559
Greece 1,520
Finland 1,503
Lithuania 1,503
Luxembourg 1,499
Latvia 1,498
Moldova 1,498
Italy 1,498
Croatia 1,498
Catalunya 1,498
United Kingdom 1,498
Romania 1,496
Portugal 1,495
Slovakia 1,493
BosniaHerzegovina 1,493
Czech Republic 1,491
Ireland 1,491
Belgium 1,490
Serbia 1,490
Cyprus 1,487
Netherlands 1,484
Slovenia 1,481
Norway 1,479
Germany 1,475
Malta 1,456
Iceland 1,445
TAUX DE VALEURS MANQUANTES PAR PAYS (sd_20month)
Source : SEAS-2 | Champ : 33 pays européens
  sd_20month
COUNTRY  
Austria 0.262257
Belgium 0.251678
BosniaHerzegovina 0.146015
Bulgaria 0.208139
Catalunya 0.295728
Croatia 0.223632
Cyprus 0.156691
Czech Republic 0.168343
Denmark 0.245198
Estonia 0.524476
Finland 0.166334
France 0.128725
Germany 0.153220
Greece 0.230263
Hungary 0.174987
Iceland 0.094810
Ireland 0.215962
Italy 0.210280
Latvia 0.377837
Lithuania 0.226880
Luxembourg 0.252168
Malta 0.188187
Moldova 0.280374
Netherlands 0.250674
Norway 0.267748
Poland 0.134060
Portugal 0.199331
Romania 0.120989
Serbia 0.215436
Slovakia 0.248493
Slovenia 1.000000
Spain 0.149635
Sweden 0.194926
United Kingdom 0.181575

Tous les pays ont un nombre conséquent d'observations (+de 1400). Nous obtiendrions donc des résultats statistiquements significatifs avec l'étude de chacun d'eux, ça n'est donc pas un critère pour sélectionner quel pays nous allons étudier. Ils ont cependant des ratio de valeurs manquantes différents pour la variable salaire mensuelle sd_month, ce qui représentera un critère de sélection. L'imputation des valeurs manquantes par sera ensuite faite seulement pour les pays sélectionnés.

Choix des pays à étudier

In [39]:
#diagramme de la moyenne de consommation d'alcool par pays (en cl d'alcool pur par an)
# lecture spécifique pour ce graphique
note_lecture = (
    "Source : The Standard European Alcohol Survey – Wave 2\n"
    "Champ : 33 pays européens\n"
    "Lecture : En moyenne en 2019, les répondants irlandais consommaient environ 3000 cl\n"
    "soit 30L d'alcool pur par an."
)

# Appel de la fonction 
cld.barplot_bycntry(
    data, 
    colonne_y='bsqf_alc', 
    y_name="consommation d'alcool pur par an (cl)", 
    titre="Consommation annuelle moyenne d'alcool pur par pays",
    source = note_lecture
)
No description has been provided for this image

On notera que la consommation bulgare devra être étudiée en détail du fait de la très grande différence en consommation absolue par rapport aux autres pays. Nous avons choisi de prendre la version non capée de bsqf_alc, il s'agira donc de voir si certains outliers ne tirent pas la consommation moyenne vers le haut.

In [40]:
#URL du GeoJSON - fond de carte europe
url = "https://raw.githubusercontent.com/datasets/geo-boundaries-world-110m/master/countries.geojson"

try:
    response = requests.get(url)
    #on lit le contenu JSON
    world = gpd.read_file(io.StringIO(response.text))
except Exception as e:
    print(f"Erreur : {e}")


world.columns = [c.upper() for c in world.columns]
europe = world[world['CONTINENT'] == 'Europe'].copy() # Filtrer l'Europe

# Fusion fond de carte/ données
# On associe les COUNTRY de notre dataset aux NAME de Geojson
map_data = europe.merge(pd.DataFrame(data), left_on='NAME', right_on='COUNTRY', how='left')

europe = europe.set_geometry('GEOMETRY')
In [41]:
# --- CARTE 1 : ALCOOL ---
texte_alc = (
    "Source : The Standard European Alcohol Survey – Wave 2\n"
    "Champ : 33 pays européens\n"
    "Lecture : En moyenne en 2019, les répondants irlandais consommaient environ 3000 cl soit 30L d'alcool pur par an."
)
cld.trace_carte_europe(data, europe, 'bsqf_alc', 
                        "Consommation moyenne annuelle d'alcool par pays", 
                        "Consommation annuelle moyenne (cl d'alcool pur)", texte_alc)
No description has been provided for this image
In [42]:
# CARTE COMPARATIVE PPA vs nomial
txt_a = (
    "Source : The Standard European Alcohol Survey – Wave 2\n"
    "Champ : 33 pays européens\n"
    "Lecture : En moyenne, en 2019, les répondants hongrois avaient\n un salaire mensuel de 670€ environ."
)
txt_b = (
    "Source : The Standard European Alcohol Survey – Wave 2 / Eurostat\n"
    "Champ : 33 pays européens\n"
    "Lecture : En moyenne, en 2019, les répondants hongrois avaient\n un salaire mensuel de 1000€ PPA environ.\n(Le salaire PPA ajuste le montant selon le coût de la vie local)."
)
cld.compare_cartes_ppa(data, europe, 'sd_20month_EUR_2020', 'sd_20month_EUR_2020_PPA', txt_a, txt_b)
No description has been provided for this image

Il y a peu de différence entre la distribution des salaires par pays en nominal et en PPA (notamment dû au large gradient de couleur qui rend moins importantes des variations de quelques centaines d'euros). La hiérarchie semble néanmoins rester la même, on utilisera donc l'une ou l'autre des unités indifféremment pour comparer les pays (en l'occurence pour nous l'euro nominal).

In [43]:
data_na = data.copy()
data_na['sd_20month_EUR_2020'] = data_na['sd_20month_EUR_2020'].isna()
data_na['RSOD_2b'] = data_na['RSOD_2b'].isna()
In [44]:
# CARTE 4 : VALEURS MANQUANTES (NA) 
texte_na = (
    "Source : The Standard European Alcohol Survey – Wave 2\n"
    "Champ : 33 pays européens\n"
    "Lecture : En moyenne, 15% des allemands interrogés n'ont pas donné leur salaire mensuel."
)

cld.trace_carte_europe(
    data=data_na, # On utilise ici le dataframe des moyennes de NA
    europe=europe, 
    colonne='sd_20month_EUR_2020', 
    titre="Ratio national moyen de valeurs manquantes pour la variable salaire mensuel sd_20month", 
    label_legende="Ratio de valeurs manquantes", 
    texte_info=texte_na
)
No description has been provided for this image

On veut étudier des pays culturellement et économiquement suffisamment différents, pour voir s'il s'en dégagent aussi des profils de consommateurs d'alcool différents. On essaye donc de choisir au moins un pays où, dans nos données,

  1. la consommation d'alcool moyenne:
    • est faible (France, Allemagne, Autriche, Islande, Chypre,etc.);
    • est élevée voire très élevée (Pologne, UK, Irlande, Grèce, Bulgarie, Estonie, Espagne,etc.);
  2. les salaires sont en moyenne:
    • élevés (Islande, Suède, Norvège,Irlande)
    • intermédiaires (France, Allemagne, Finlande, Pays- Bas, etc.)
    • faible (Hongrie, Portugal, Pologne, Serbie, etc.)

Parmi ces pays, on essaye de choisir ceux qui n'ont pas trop de valeurs manquantes surtout pour la variables sd_20month pour les raisons évoquées ci-avant. On essaye également de choisir des pays à différents endroits du continents européens pour voir l'influence des caractéristiques culturelles (ex: type de boissons consommées selon les espaces géographiques).

Ces considérations nous conduisent à choisir les quatres pays suivants: la Bulgarie, la France, l'Islande et la Pologne.

Partie II : Analyses et traitements¶

A. Statistiques descriptives¶

In [45]:
country = ['France', 'Poland', 'Iceland', 'Bulgaria']
data1 = data[data['COUNTRY'].isin(country)].copy()

#style général pour l'affichage des stats desc
sns.set_theme(style="whitegrid", context="talk")
In [46]:
vars_audit = [
    'SD_1', 'SD_2', 'SD_9', 'social_class',  
    'sd_20month_EUR_2020',                            
    'bsqf_alc', 'RSOD_2b',      
]
std.tableau_qualite_par_pays(data1, vars_audit)
==================================================
 RAPPORT QUALITÉ DES DONNÉES PAR PAYS
==================================================
Out[46]:
N_Total % Manquant (NaN) % Refus (Refusal)
Pays Bulgaria France Iceland Poland Bulgaria France Iceland Poland Bulgaria France Iceland Poland
Variable
RSOD_2b 2998 1678 1445 1559 9.4 38.7 33.2 9.8 0.0 0.0 0.0 0.0
SD_1 2998 1678 1445 1559 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
SD_2 2998 1678 1445 1559 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
SD_9 2998 1678 1445 1559 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
bsqf_alc 2998 1678 1445 1559 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
sd_20month_EUR_2020 2998 1678 1445 1559 20.8 12.9 9.5 13.4 0.0 0.0 0.0 0.0
social_class 2998 1678 1445 1559 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
In [47]:
vars_audit= ['WB_1', 'WB_2', 'WB_3']
codes_refus = [6]
std.tableau_qualite_par_pays(data1, vars_audit, codes_refus)
==================================================
 RAPPORT QUALITÉ DES DONNÉES PAR PAYS
==================================================
Out[47]:
N_Total % Manquant (NaN) % Refus (Refusal)
Pays Bulgaria France Iceland Poland Bulgaria France Iceland Poland Bulgaria France Iceland Poland
Variable
WB_1 2998 1678 1445 1559 0.0 0.0 0.0 0.0 0.3 0.6 0.1 0.3
WB_2 2998 1678 1445 1559 0.0 0.0 0.0 0.0 0.2 0.5 0.1 0.2
WB_3 2998 1678 1445 1559 0.0 0.0 0.0 0.0 0.3 0.6 0.0 0.1
In [48]:
vars_audit = [
    'SD_1', 'SD_2', 'SD_9', 'social_class',  
    'sd_20month_EUR_2020',                            
    'bsqf_alc', 'WB_1', 'WB_2', 'WB_3', 'RSOD_2b',      
]
std.heatmap_manquants(data1, vars_audit)
No description has been provided for this image

Avant de lancer les analyses, un audit rapide de la base montre que les données sont globalement très saines. En effet, on peut voir que nous n'avons aucune valeur manquante sur les variables clés (âge, sexe, éducation, classe sociale) pour les quatre pays. Cela nous facilitera la comparaison des profils de consommateurs entre les pays.

Cependant,Comme souvent dans les enquêtes, le revenu mensuel (sd_20month_EUR_2020) comporte beaucoup de trous, surtout en Bulgarie (21 % de manquants) et en Pologne/France. Plutôt que de supprimer ces individus, nous procederons a une imputation par des regressions, de meme que pour les variables de binge drinking (RSOD_2b).

In [49]:
# Matching des variables
map_marital = {
    1: "Married/Living together",
    2: "Married/Living apart",
    3: "Never married",
    4: "Divorced",
    5: "Widowed"
}

map_residence = {
    1: "Village/Farm",
    2: "Small city (<50k)",
    3: "Medium city (50k-250k)",
    4: "Large city (250k-1M)",
    5: "Very large city (>1M)"
}

map_education = {
    1: "Primary",
    2: "Secondary",
    3: "Vocational",
    4: "University/Higher",
    5: "No schooling"
}

map_pro_status = {
    1: "Active",
    2: "Non-active"
}

map_social_class = {
    1: "Blue collar",
    2: "White collar",
    3: "Manager/Professional",
    4: "Business person",
    5: "Other",
    9: "No answer"
}


data1['Marital_Label'] = data1['SD_4'].map(map_marital)
data1['Residence_Label'] = data1['SD_8'].map(map_residence)
data1['Education_Label'] = data1['SD_9'].map(map_education)
data1['Activity_Label'] = data1['SD_10'].map(map_pro_status)
data1['Class_Label'] = data1['social_class'].map(map_social_class)
In [50]:
std.analyse_cat(data1, 'Marital_Label', 'Statut Marital')
std.analyse_cat(data1, 'Residence_Label', 'Type de Résidence')
std.analyse_cat(data1, 'Education_Label', "Niveau d'Éducation")
std.analyse_cat(data1, 'Activity_Label', 'Statut Professionnel')
std.analyse_cat(data1, 'Class_Label', 'classe sociale')
========================================
 ANALYSE : Statut Marital (Marital_Label)
========================================
>>> Tableau des Pourcentages (%) :
Marital_Label  Divorced  Married/Living apart  Married/Living together  \
COUNTRY                                                                  
Bulgaria            8.9                   5.0                     52.7   
France              8.5                   4.1                     51.9   
Iceland             6.2                   2.1                     58.0   
Poland              6.4                   7.3                     63.0   

Marital_Label  Never married  Widowed  
COUNTRY                                
Bulgaria                31.2      2.2  
France                  34.3      1.3  
Iceland                 32.6      1.2  
Poland                  22.1      1.2  

>>> Tableau des Effectifs (N) :
Marital_Label  Divorced  Married/Living apart  Married/Living together  \
COUNTRY                                                                  
Bulgaria            267                   149                     1580   
France              142                    69                      871   
Iceland              89                    30                      838   
Poland              100                   114                      982   

Marital_Label  Never married  Widowed  
COUNTRY                                
Bulgaria                 936       66  
France                   575       21  
Iceland                  471       17  
Poland                   344       19  
No description has been provided for this image
========================================
 ANALYSE : Type de Résidence (Residence_Label)
========================================
>>> Tableau des Pourcentages (%) :
Residence_Label  Large city (250k-1M)  Medium city (50k-250k)  \
COUNTRY                                                         
Bulgaria                         20.6                    21.8   
France                            9.2                    22.1   
Iceland                           9.6                    37.9   
Poland                           20.3                    26.6   

Residence_Label  Small city (<50k)  Very large city (>1M)  Village/Farm  
COUNTRY                                                                  
Bulgaria                      21.3                   29.7           6.5  
France                        35.0                    6.4          27.3  
Iceland                       42.5                    1.9           8.2  
Poland                        24.2                   10.1          18.8  

>>> Tableau des Effectifs (N) :
Residence_Label  Large city (250k-1M)  Medium city (50k-250k)  \
COUNTRY                                                         
Bulgaria                          618                     655   
France                            155                     371   
Iceland                           138                     548   
Poland                            317                     414   

Residence_Label  Small city (<50k)  Very large city (>1M)  Village/Farm  
COUNTRY                                                                  
Bulgaria                       638                    891           196  
France                         587                    107           458  
Iceland                        614                     27           118  
Poland                         378                    157           293  
No description has been provided for this image
========================================
 ANALYSE : Niveau d'Éducation (Education_Label)
========================================
>>> Tableau des Pourcentages (%) :
Education_Label  No schooling  Primary  Secondary  University/Higher  \
COUNTRY                                                                
Bulgaria                  0.2      0.3        1.5               59.1   
France                    0.1      0.6       18.8               56.0   
Iceland                   0.1      4.9        9.9               69.8   
Poland                    0.3     10.0       35.5               45.2   

Education_Label  Vocational  
COUNTRY                      
Bulgaria               38.9  
France                 24.6  
Iceland                15.2  
Poland                  9.1  

>>> Tableau des Effectifs (N) :
Education_Label  No schooling  Primary  Secondary  University/Higher  \
COUNTRY                                                                
Bulgaria                    6        8         46               1773   
France                      1       10        316                939   
Iceland                     2       71        143               1009   
Poland                      4      156        553                704   

Education_Label  Vocational  
COUNTRY                      
Bulgaria               1165  
France                  412  
Iceland                 220  
Poland                  142  
No description has been provided for this image
========================================
 ANALYSE : Statut Professionnel (Activity_Label)
========================================
>>> Tableau des Pourcentages (%) :
Activity_Label  Active  Non-active
COUNTRY                           
Bulgaria          75.9        24.1
France            72.2        27.8
Iceland           72.7        27.3
Poland            74.1        25.9

>>> Tableau des Effectifs (N) :
Activity_Label  Active  Non-active
COUNTRY                           
Bulgaria          2275         723
France            1212         466
Iceland           1051         394
Poland            1155         404
No description has been provided for this image
========================================
 ANALYSE : classe sociale (Class_Label)
========================================
>>> Tableau des Pourcentages (%) :
Class_Label  Blue collar  Business person  Manager/Professional  No answer  \
COUNTRY                                                                      
Bulgaria            22.5              6.4                  23.4       24.1   
France              18.7              5.2                  22.5       27.8   
Iceland             11.6             12.3                  37.9       27.3   
Poland              25.8              3.1                  21.8       25.9   

Class_Label  Other  White collar  
COUNTRY                           
Bulgaria       8.8          14.7  
France         5.3          20.5  
Iceland        0.2          10.7  
Poland         3.7          19.6  

>>> Tableau des Effectifs (N) :
Class_Label  Blue collar  Business person  Manager/Professional  No answer  \
COUNTRY                                                                      
Bulgaria             675              192                   703        723   
France               314               88                   377        466   
Iceland              167              178                   548        394   
Poland               402               49                   340        404   

Class_Label  Other  White collar  
COUNTRY                           
Bulgaria       265           440  
France          89           344  
Iceland          3           155  
Poland          58           306  
No description has been provided for this image

Synthese des profils socio-demographiques:

On observe ci-dessus des structures culturelles bien distinctes selon les pays. La Pologne se détache comme le pays le plus « traditionnel », avec une nette majorité de personnes mariées (63 %), là où la France et l'Islande comptent beaucoup plus de célibataires. Géographiquement, c'est la Bulgarie qui surprend par sa polarisation extrême : ses habitants vivent soit dans la capitale et les très grandes villes, soit au village, sans grand entre-deux.

Le niveau d'éducation est un autre facteur de différenciation majeur. L'échantillon islandais est particulièrement instruit (70 % de niveau universitaire), ce qui contraste avec une Pologne dont le socle principal reste l'enseignement secondaire. Cela aura forcément un impact sur l'analyse des comportements de santé, même si le taux d'emploi, lui, est identique partout (environ 75 % d'actifs).

In [51]:
std.analyse_num(data1, 'SD_2', 'Âge des répondants')
std.analyse_num(data1, 'sd_20month_EUR_2020', 'Revenu Mensuel (en Euros)')
========================================
 ANALYSE : Âge des répondants (SD_2)
========================================
          Moyenne  Médiane  Ecart-Type   IQR  Min  Max   P10   P90
COUNTRY                                                           
Bulgaria    40.51     41.0       11.62  18.0   18   64  24.0  56.0
France      42.01     42.0       12.86  22.0   18   64  25.0  60.0
Iceland     40.04     38.0       11.56  14.0   18   64  26.0  56.0
Poland      39.91     40.0       12.78  20.5   18   64  22.0  58.0
c:\Users\Utilisateur\Documents\Téléchargements\Anaconda\Lib\site-packages\seaborn\_oldcore.py:1119: FutureWarning: use_inf_as_na option is deprecated and will be removed in a future version. Convert inf values to NaN before operating instead.
  with pd.option_context('mode.use_inf_as_na', True):
c:\Users\Utilisateur\Documents\Téléchargements\Anaconda\Lib\site-packages\seaborn\_oldcore.py:1075: FutureWarning: When grouping with a length-1 list-like, you will need to pass a length-1 tuple to get_group in a future version of pandas. Pass `(name,)` instead of `name` to silence this warning.
  data_subset = grouped_data.get_group(pd_key)
c:\Users\Utilisateur\Documents\Téléchargements\Anaconda\Lib\site-packages\seaborn\_oldcore.py:1075: FutureWarning: When grouping with a length-1 list-like, you will need to pass a length-1 tuple to get_group in a future version of pandas. Pass `(name,)` instead of `name` to silence this warning.
  data_subset = grouped_data.get_group(pd_key)
c:\Users\Utilisateur\Documents\Téléchargements\Anaconda\Lib\site-packages\seaborn\_oldcore.py:1075: FutureWarning: When grouping with a length-1 list-like, you will need to pass a length-1 tuple to get_group in a future version of pandas. Pass `(name,)` instead of `name` to silence this warning.
  data_subset = grouped_data.get_group(pd_key)
No description has been provided for this image
========================================
 ANALYSE : Revenu Mensuel (en Euros) (sd_20month_EUR_2020)
========================================
          Moyenne  Médiane  Ecart-Type      IQR      Min       Max      P10  \
COUNTRY                                                                       
Bulgaria  1020.47   895.03      587.47   715.56    95.87   2300.85   409.04   
France    4041.78  3000.00     2743.40  3450.00  1500.00   9000.00  1500.00   
Iceland   5070.42  4869.73     2151.62  2130.51  1533.97  10080.35  1533.97   
Poland    1301.35  1175.25      592.81   940.20   264.43   2291.75   587.63   

              P90  
COUNTRY            
Bulgaria  2045.20  
France    9000.00  
Iceland   7304.60  
Poland    2291.75  
c:\Users\Utilisateur\Documents\Téléchargements\Anaconda\Lib\site-packages\seaborn\_oldcore.py:1119: FutureWarning: use_inf_as_na option is deprecated and will be removed in a future version. Convert inf values to NaN before operating instead.
  with pd.option_context('mode.use_inf_as_na', True):
c:\Users\Utilisateur\Documents\Téléchargements\Anaconda\Lib\site-packages\seaborn\_oldcore.py:1075: FutureWarning: When grouping with a length-1 list-like, you will need to pass a length-1 tuple to get_group in a future version of pandas. Pass `(name,)` instead of `name` to silence this warning.
  data_subset = grouped_data.get_group(pd_key)
c:\Users\Utilisateur\Documents\Téléchargements\Anaconda\Lib\site-packages\seaborn\_oldcore.py:1075: FutureWarning: When grouping with a length-1 list-like, you will need to pass a length-1 tuple to get_group in a future version of pandas. Pass `(name,)` instead of `name` to silence this warning.
  data_subset = grouped_data.get_group(pd_key)
c:\Users\Utilisateur\Documents\Téléchargements\Anaconda\Lib\site-packages\seaborn\_oldcore.py:1075: FutureWarning: When grouping with a length-1 list-like, you will need to pass a length-1 tuple to get_group in a future version of pandas. Pass `(name,)` instead of `name` to silence this warning.
  data_subset = grouped_data.get_group(pd_key)
No description has been provided for this image

On observe une structure d'age relativement homogene, les échantillons sont parfaitement alignés entre les quatre pays. La moyenne d'âge gravite partout autour de 40-42 ans, avec une couverture stricte de la population active (de 18 à 64 ans). On note une légère nuance pour l'Islande, qui présente une population un peu plus jeune (médiane à 38 ans contre 42 en France) et une densité plus forte sur les trentenaires. Cependant, ces écarts sont minimes. Ainsi, si l'on observe des différences de consommation d'alcool, elles ne seront pas dues à un effet de structure (par exemple, un pays qui serait beaucoup plus "vieux" qu'un autre).

À l'inverse de l'âge, la distribution des revenus mensuels (convertis en euros) illustre le fossé économique entre les pays étudiés. On distingue clairement deux groupes : -Le groupe "Hauts Revenus" : L'Islande domine largement avec un revenu médian autour de 4 800 €, suivie par la France (médiane à 2 925 €). La France se distingue par une forte inégalité : la moyenne (4 020 €) est bien supérieure à la médiane, tirée par des hauts revenus, ce qui se voit sur l'étalement de la courbe de densité. -Le groupe "Revenus Modestes" : La Pologne et la Bulgarie présentent des distributions beaucoup plus resserrées et concentrées vers le bas, avec des médianes respectives de 1 175 € et 895 €.

In [52]:
std.preferences_alcool(data1)
No description has been provided for this image
In [53]:
std.ecart_hommes_femmes(data1)
No description has been provided for this image

Les hommes consomment plus d'alcool que les femmes dans tous les pays mais dans des proportion très différentes selon les pays. Les polonais consomment environ deux fois plus que les polonaises mais les islandais consomment presque le même volume que les islandaises. Le sexe semble donc être davantage un déterminant de la consommation d'alcool en Pologne et en Bulgarie.

In [54]:
std.evolution_par_age(data1)
c:\Users\Utilisateur\Documents\Téléchargements\Anaconda\Lib\site-packages\seaborn\_oldcore.py:1119: FutureWarning: use_inf_as_na option is deprecated and will be removed in a future version. Convert inf values to NaN before operating instead.
  with pd.option_context('mode.use_inf_as_na', True):
c:\Users\Utilisateur\Documents\Téléchargements\Anaconda\Lib\site-packages\seaborn\_oldcore.py:1119: FutureWarning: use_inf_as_na option is deprecated and will be removed in a future version. Convert inf values to NaN before operating instead.
  with pd.option_context('mode.use_inf_as_na', True):
c:\Users\Utilisateur\Documents\Téléchargements\Anaconda\Lib\site-packages\seaborn\_oldcore.py:1075: FutureWarning: When grouping with a length-1 list-like, you will need to pass a length-1 tuple to get_group in a future version of pandas. Pass `(name,)` instead of `name` to silence this warning.
  data_subset = grouped_data.get_group(pd_key)
c:\Users\Utilisateur\Documents\Téléchargements\Anaconda\Lib\site-packages\seaborn\relational.py:441: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  sub_data = grouped.apply(agg, other).reset_index()
c:\Users\Utilisateur\Documents\Téléchargements\Anaconda\Lib\site-packages\seaborn\_oldcore.py:1075: FutureWarning: When grouping with a length-1 list-like, you will need to pass a length-1 tuple to get_group in a future version of pandas. Pass `(name,)` instead of `name` to silence this warning.
  data_subset = grouped_data.get_group(pd_key)
c:\Users\Utilisateur\Documents\Téléchargements\Anaconda\Lib\site-packages\seaborn\relational.py:441: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  sub_data = grouped.apply(agg, other).reset_index()
c:\Users\Utilisateur\Documents\Téléchargements\Anaconda\Lib\site-packages\seaborn\_oldcore.py:1075: FutureWarning: When grouping with a length-1 list-like, you will need to pass a length-1 tuple to get_group in a future version of pandas. Pass `(name,)` instead of `name` to silence this warning.
  data_subset = grouped_data.get_group(pd_key)
c:\Users\Utilisateur\Documents\Téléchargements\Anaconda\Lib\site-packages\seaborn\relational.py:441: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  sub_data = grouped.apply(agg, other).reset_index()
c:\Users\Utilisateur\Documents\Téléchargements\Anaconda\Lib\site-packages\seaborn\_oldcore.py:1075: FutureWarning: When grouping with a length-1 list-like, you will need to pass a length-1 tuple to get_group in a future version of pandas. Pass `(name,)` instead of `name` to silence this warning.
  data_subset = grouped_data.get_group(pd_key)
c:\Users\Utilisateur\Documents\Téléchargements\Anaconda\Lib\site-packages\seaborn\relational.py:441: FutureWarning: DataFrameGroupBy.apply operated on the grouping columns. This behavior is deprecated, and in a future version of pandas the grouping columns will be excluded from the operation. Either pass `include_groups=False` to exclude the groupings or explicitly select the grouping columns after groupby to silence this warning.
  sub_data = grouped.apply(agg, other).reset_index()
No description has been provided for this image
In [55]:
std.analyse_intensite_annuelle(data1, log_scale=True)
========================================
(a) INTENSITÉ ANNUELLE (bsqf_alc)
========================================
>>> Indicateurs de distribution :
            mean  median     iqr     p90      p95
COUNTRY                                          
Bulgaria  5429.0   660.1  2020.0  6420.9  14448.4
France     585.7   179.1   555.6  1434.7   2309.1
Iceland    242.6    60.0   181.6   577.3   1133.5
Poland    2627.6   537.3  1302.5  3555.6   6418.6
c:\Users\Utilisateur\Documents\Téléchargements\Anaconda\Lib\site-packages\seaborn\_oldcore.py:1119: FutureWarning: use_inf_as_na option is deprecated and will be removed in a future version. Convert inf values to NaN before operating instead.
  with pd.option_context('mode.use_inf_as_na', True):
c:\Users\Utilisateur\Documents\Téléchargements\Anaconda\Lib\site-packages\seaborn\_oldcore.py:1075: FutureWarning: When grouping with a length-1 list-like, you will need to pass a length-1 tuple to get_group in a future version of pandas. Pass `(name,)` instead of `name` to silence this warning.
  data_subset = grouped_data.get_group(pd_key)
c:\Users\Utilisateur\Documents\Téléchargements\Anaconda\Lib\site-packages\seaborn\_oldcore.py:1075: FutureWarning: When grouping with a length-1 list-like, you will need to pass a length-1 tuple to get_group in a future version of pandas. Pass `(name,)` instead of `name` to silence this warning.
  data_subset = grouped_data.get_group(pd_key)
No description has been provided for this image

On voit ici que la Bulgarie et la Pologne se distinguent par les médianes de consommation les plus élevées et des distributions étalées vers le haut, signalant une part importante de gros consommateurs. À l'opposé, l'Islande affiche une consommation globale très faible, avec une médiane écrasée vers le bas.

In [56]:
std.analyse_rsod_frequence(data1)
========================================
(d-1) FRÉQUENCE BINGE DRINKING (RSOD_2b)
========================================
Distribution des fréquences RSOD (%) :
RSOD_Simple  1 - 2 days a week  1 day in a month  2-3 days a month  \
COUNTRY                                                              
Bulgaria                  10.7               6.8              14.8   
France                     7.8               7.7              11.1   
Iceland                    6.3               3.4               7.7   
Poland                    19.0              14.0              15.4   

RSOD_Simple  2-5 days a year  3-4 days a week  5-6 days a week  \
COUNTRY                                                          
Bulgaria                12.4             11.7              7.2   
France                  16.2              6.1              1.1   
Iceland                 11.8              2.5              0.7   
Poland                  14.1              6.0              2.8   

RSOD_Simple  6-11 days a year  Every day  \
COUNTRY                                    
Bulgaria                 14.8        5.3   
France                   11.0        2.5   
Iceland                   5.7        0.8   
Poland                    9.7        2.5   

RSOD_Simple  I did not drink in the past 12 months  \
COUNTRY                                              
Bulgaria                                       4.9   
France                                        20.9   
Iceland                                       22.4   
Poland                                         5.0   

RSOD_Simple  a single day in the past 12 months  
COUNTRY                                          
Bulgaria                                   11.4  
France                                     15.6  
Iceland                                    38.7  
Poland                                     11.6  
No description has been provided for this image
In [57]:
std.analyse_composition(data1)
========================================
(c) COMPOSITION DU PANIER (Mix Alcool)
========================================
>>> Mix Moyen (%) par Pays :
          Share_Beer  Share_Wine  Share_Spir
COUNTRY                                     
Bulgaria        37.1        31.2        31.7
France          43.8        42.6        13.6
Iceland         47.2        35.0        17.8
Poland          49.9        26.8        23.3
No description has been provided for this image

En matiere de type d'alcool consommé, la France reste incontestablement le pays du vin, qui représente 43 % du volume d'alcool ingéré, loin devant les autres pays. La Pologne (50 %) et l'Islande (47 %) en revanche sont des terres de bière. La Bulgarie quant a elle est le seul pays où les spiritueux (alcools forts) occupent une place aussi massive (32 % du marché), talonnant la bière.

B. Imputation des données¶

Stratégie d'Imputation des Données Manquantes¶

1. Contexte et Approche Stratifiée par Pays¶

La base de données traitée présente une forte hétérogénéité structurelle due à la diversité des pays inclus.

Afin d'éviter le biais d'écrasement qu'aurait provoqué une imputation globale, nous avons opté pour une approche stratifiée par pays.

  • Justification : Un revenu de 2000€ n'a pas la même signification économique ni le même pouvoir prédictif en France qu'en Pologne. De même, les modèles de consommation d'alcool sont fortement culturels.
  • Décision : Chaque modèle d'imputation a été entraîné et appliqué exclusivement sur les sous-ensembles de données nationaux, garantissant le respect des distributions et des corrélations locales.

2. Imputation du Salaire mensuel ('sd_20month_EUR_2020): Approche par Modélisation Prédictive¶

Pour la variable Salaire (variable quantitative continue), nous avons rejeté les imputations univariées simplistes (moyenne/médiane) qui réduisent la variance et faussent les analyses de corrélation ultérieures.

Nous avons privilégié une approche par Régression Supervisée (Random Forest ) pour les raisons suivantes :

  • Préservation de la Structure de Corrélation : Le salaire est fortement déterminé par des variables explicatives présentes dans la base. L'utilisation d'un modèle prédictif permet de reconstruire le salaire théorique d'un individu en fonction de son profil socio-démographique précis.
  • Gestion de la Non-Linéarité : Contrairement à une régression linéaire simple, les modèles d'ensemble comme le randaom Forest capturent les effets de seuil et les interactions complexes.

3. Imputation de la Fréquence de Consommation et du Nombre d'enfant de moins de 18 ans dans le ménage : Approche par KNN¶

Pour les variables Fréquence de grosse consommation (RSOD_2b) et Nombre de mineurs dans le ménage (SD_7), nous avons opté pour l'algorithme des K-Plus Proches Voisins (KNN).

Ce choix se justifie par la nature de ces variables et la logique sociologique sous-jacente :

  • Nature des Variables (Ordinales/Discrètes) :

  • La fréquence de consommation est une variable ordinale (échelle de 1 à 10).

  • Le nombre de mineurs est une variable discrète.

  • L'utilisation d'une régression aurait produit des valeurs continues aberrantes. Le KNN, en faisant la moyenne locale, reste plus cohérent avec des valeurs discrètes.

  • Logique de "Profils Similaires" : les comportements (boire de l'alcool) et les structures familiales (avoir des enfants) tendent à être partagés par des individus ayant des caractéristiques proches (même âge, même milieu social).

In [58]:
data = ipt.imputer_salaire_pays(data)
Début de l'imputation pour 4 pays...

--- Performances du modèle pour France ---
Score R² : 0.9512
RMSE : 0.14
--------------------------------------------

--- Performances du modèle pour Iceland ---
Score R² : 0.9315
RMSE : 0.13
--------------------------------------------

--- Performances du modèle pour Bulgaria ---
Score R² : 0.9182
RMSE : 0.18
--------------------------------------------

--- Performances du modèle pour Poland ---
Score R² : 0.9333
RMSE : 0.13
--------------------------------------------


--- Imputation terminée pour tous les pays ---
In [59]:
data = ipt.imputer_knn(data)
 Imputation terminée.
In [60]:
pays_selectionnes = ["France", "Bulgaria", "Poland", "Iceland"]
data = data[data["COUNTRY"].isin(pays_selectionnes)]
stats_na = cld.tableau_na(data)
stats_na
Out[60]:
TABLEAU RÉCAPITULATIF DES DONNÉES MANQUANTES
Source : The Standard European Alcohol Survey – Wave 2 | Champ : 33 pays européens
Variable Taux de manquants
COUNTRY 0.00%
SD_1 0.00%
SD_2 0.00%
SD_4 0.00%
SD_6 0.00%
SD_7 0.00%
SD_8 0.00%
SD_9 0.00%
SD_10 0.00%
sd_20month 15.44%
social_class 0.00%
bsqf_alc 0.00%
f_1b 0.00%
cbsqf_beer 0.00%
cbsqf_spir 0.00%
cbsqf_wine 0.00%
RSOD_2b 0.00%
CH_1 0.00%
WB_1 0.00%
WB_2 0.00%
WB_3 0.00%
EXCHANGE_RATE_TO_EUR 0.00%
sd_20month_EUR_2020 0.00%
PPA 0.00%
sd_20month_EUR_2020_PPA 15.44%
RSOD_2bisna 0.00%

C. Analyses factorielles (ACM & ACP)¶

ACP/ACM France¶

ACP France

In [61]:
# Sélection des variables quantitatives 
quanti = data[[
    "SD_2",          # Âge 
    "SD_7",          # Nombre de mineurs au foyer 
    "sd_20month_EUR_2020",    # Revenu mensuel 
    "bsqf_alc",      # Consommation annuelle totale d'alcool 
    "cbsqf_beer",    # Consommation annuelle de bière(plafonnée) 
    "cbsqf_spir",    # Consommation annuelle de spiritueux (plafonnée) 
    "cbsqf_wine"     # Consommation annuelle de vin (plafonnée) 
]]

# Sélection des variables qualitatives 
quali = data[[
    "COUNTRY",       # Pays de résidence
    "SD_1",          # Genre 
    "SD_4",          # Statut matrimonial 
    "SD_6",          # vie seul ou non
    "SD_8",          # Type de lieu de résidence 
    "SD_9",          # Niveau d'éducation 
    "SD_10",         # Statut d'activité professionnelle 
    "social_class",  # Classe sociale auto-déclarée 
    "f_1b",          # Fréquence générique de consommation 
    "RSOD_2b",       # Fréquence de consommation de 4/6+ verres 
    "CH_1",          # Contact avec un gros buveur durant l'enfance 
    "WB_1",          # État de santé général 
    "WB_2",          # Bien-être psychologique 
    "WB_3"           # Satisfaction des relations sociales
]]
In [62]:
# On calcule l'ACP sur les quanti.colums/ variables quantitatives
pca_fr, feat_fr, cols_fr = dtn.calculer_acp_pays(data, "France", quanti.columns)

# Et on trace
if pca_fr is not None:
    dtn.trace_cercle_et_variance(pca_fr, cols_fr, "FRANCE")
No description has been provided for this image

La première dimension explique 40% de la variance et la deuxième environ 17.5%, on capture donc déjà beaucoup de variabilité en étudiant ces deux premières dimensions notamment la première. On voit sur le cercle des corrélations qu'aucune variable n'explique extrêmement bien la première dimension, les variables qui lui sont les plus corrélées sont la consommation d'alcool annuelle (bsqf_alc) et de bière en particulier (bsqf__beer). Les variables SD_7 (le nombre de mineur dans le foyer) et l'âge SD_2 sont très bien représentées sur le second axe. On remarquera logiquement que SD_2 et SD_7 ont la même direction mais des sens totalement opposés sur l'axe 2, c'est logique plus on avance en âge, moins on a d'enfants à charge au foyer, cette ACP capte bien une structure démographique logique dans les données française.

Le fait que le vecteur associé à la consommation de vin (cbsqf_wine) pointe légèrement plus vers le haut que celle de bière ou de spiritueux (vers le sens de l'âge SD_2 qui explique très bien l'axe 2) suggère qu'en France, la consommation de vin est plus corrélée aux profils plus âgés.

Les matrices de variance des ACP de chaque pays sont dans la partie II de l'annexe.

On va maintenant calculer les cos^2 des individus sur les deux premiers axes, c'est à dire la qualité de leur représentation sur ces axes.

In [63]:
meilleur_index1, meilleur_index2 = dtn.tracer_cos2_individus(data, "France", quanti.columns, pca_fr, n_top=10)
No description has been provided for this image

On voit que le cos^2 des individus les mieux projetés sur chaque axe sont entre 0.8 et 1 ce qui est assez proche de 1, ces individus sont donc très représentatifs d'un de ces deux premiers axes. Par exemple, l'individu 32010 est très représentatif de l'axe 1 et l'individu 36176 est très représentatif de l'axe 2.

In [64]:
# On lève la limite sur le nombre de colonnes affichées
pd.set_option('display.max_columns', None)
# On affiche le profil / la ligne dans le dataset pour les individus ayant les plus gros cos2 pour l'axe 1 et 2
display(data.loc[[meilleur_index1]], data.loc[[meilleur_index2 ]] )
COUNTRY SD_1 SD_2 SD_4 SD_6 SD_7 SD_8 SD_9 SD_10 sd_20month social_class bsqf_alc f_1b cbsqf_beer cbsqf_spir cbsqf_wine RSOD_2b CH_1 WB_1 WB_2 WB_3 EXCHANGE_RATE_TO_EUR sd_20month_EUR_2020 PPA sd_20month_EUR_2020_PPA RSOD_2bisna
32010 France 2 31 2 2 2.0 2 4 1 2750.0 1 34711.5 1 18250.0 9855.0 4380.0 1.0 1 2 2 2 1.0 2750.0 1.08489 2534.819198 0
COUNTRY SD_1 SD_2 SD_4 SD_6 SD_7 SD_8 SD_9 SD_10 sd_20month social_class bsqf_alc f_1b cbsqf_beer cbsqf_spir cbsqf_wine RSOD_2b CH_1 WB_1 WB_2 WB_3 EXCHANGE_RATE_TO_EUR sd_20month_EUR_2020 PPA sd_20month_EUR_2020_PPA RSOD_2bisna
31298 France 2 19 2 1 2.0 2 4 1 2250.0 4 68.5 4 42.5 8.5 17.5 8.0 1 1 1 2 1.0 2250.0 1.08489 2073.94298 0

Individu 32010 : Le profil de l'Axe 1 Identité :

  • C'est une femme de 31 ans.

  • Foyer : Elle vit avec 2 enfants mineurs.

  • Revenu : Elle gagne 2 750 € par mois.

  • Consommation : Elle boit 347 L d'alcool par an au total (ce qui est, disons le, beaucoup trop pour être crédible)!!

  • Détail : Sa consommation d'alcool est en majorité de la bière.

  • Santé : Elle a un score de bien-être physique et mental de 2 (= "good" sur une échelle où 1 (="very good") est le maximum).

Individu 36176 : Le profil de l'Axe 2

  • Identité : C'est un homme de 56 ans.

  • Foyer : Il n'a aucun enfant mineur à charge.

  • Revenu : Il gagne 5 550 € par mois.

  • Consommation : Il boit 615 cl soit 6.15L d'alcool par an au total.

  • Détail : Sa consommation est plus diversifiée mais beaucoup plus faible en volume que l'individu précédent.

  • Santé : Il a un score de bien-être physique et santé mental de 1 ("Very good"), et un score de satistaction dans les relations sociales de 2 ("good")

Puisque sur l'axe 1, ne sont bien représentées que des variables liées à l'alcool et sur l'axe 2 ne sont bien représentées que des variables non relatives à la consommation d'alcool, il nous semble difficile de déduire une interprétation généralisable sur le profil des consommateurs français via cette ACP. En effet, par exemple, l'individu 32010 est archétypique d'une forte consommatrice d'alcool tandis que le 36176 est archétypique d'une liaison entre haut revenu, âge élevé et baisse du nombre d'enfant dans le foyer mais ne dit pas grand chose sur la consommation d'alcool.

Mais donc l'ACP semble révéler que le profil de consommation (Axe 1) et le profil de vie (Axe 2) sont déconnectés. Cela suggère que la consommation d'alcool en France est un phénomène qui traverse toute la distribution de revenu et tous les âges : on peut être un 'gros consommateur' (Axe 1+) quel que soit son profil familial/économique (Axe 2).

ACM France

In [65]:
#On recode certaines variables pour rendre l'ACM plus facilement interprétable

# Recodage du REVENU (sd_20month)
# On le découpe en quartiles
df_acm= data.copy()
df_acm['sd_20month_EUR_2020'] = pd.qcut(df_acm['sd_20month_EUR_2020'], q=4, labels=['Revenu_quartile1', 'Revenu_quartile2', 'Revenu_quartile3','Revenu_quartile4'])
df_acm['RSOD_2b'] = df_acm['RSOD_2b'].apply(dtn.simplifier_rsod)#recodage du binge drinking en 4 catégories (cf Data_analysis.py)
df_acm['f_1b'] = df_acm['f_1b'].apply(dtn.recoder_f1b)#recodage de la fréquence de consommation d'alcool en 4 catégories

Avant de faire l'ACM, on doit choisir les variables qui sont actives, c'est à dire qui participent à la construction des axes. Elles permettront alors de comprendre les liens entre les modalités (la plus ou moins forte consommation d'alcool ou le genre par exemple) et de repérer la prévalence de ces modalités pour des groupes d'individus par exemple. On fixe ce que l'on cherche : trouver des liens entre la consommation d'alcool et des caractéristiques intrinsèques des individus (socio-économique notamment). C'est donc les variables qui décrivent cela que l'on doit prendre comme variables actives. Ensuite, nous choisissons quelques variables illustratives pertinentes au vue de la littérature et des analyses descriptives précédentes (elles peuvent être qualitatives ou quantitatives - donc on peut y mettre la consommation d'alcool bsqf_alc notamment). Ces variables ne sont pas utilisées pour la construction des axes, mais sont projetées a posteriori sur les axes pour enrichir, si possible, l'interprétation. En suivant cette idée, on fait les choix suivant:

In [66]:
# Variables Actives
actives = [
    "sd_20month_EUR_2020", "f_1b", "RSOD_2b", "SD_9", "SD_1", 
    "social_class", "WB_1", "WB_2", "WB_3",]
    
# Variables Illustratives
illustratives = [ "SD_2", "SD_6", "SD_8"," SD_7", "cbsqf","cbsqf_beer", "cbsqf_spir", "cbsqf_wine"]

On a choisi un peu arbitrairement de réduire l'ACM à trois dimensions, cela permet de dégager les grandes tendances en étudiant les deux premières. Nous avons essayé avec 8 dimensions et les résultats/interprétations qui s'en suivaient ne changeaient pas significativement.

In [67]:
mca_fr = dtn.fait_acm(df_acm, "France", actives)
dtn.plot_var_acm(mca_fr, "France")
No description has been provided for this image

La première dimension explique 38% de la variance des données des variables actives et la seconde 33 %. Ces deux dimensions expliquent une grande part de la variance et on peut se concentrer sur elles.

Comme le nombre de modalités est trop important pour être bien lisible en représantation graphique, on regarde plutôt pour commencer le lien entre chacune des deux premières dimensions et les variables actives.

In [68]:
#graphe des contributions de chaque variables aux 2 premiers axes
dtn.tracer_graphe_liaisons(mca_fr, "France")
No description has been provided for this image

On voit que la première dimension est surtout liée ( mais pas très fortement ~0.25) aux variables WB_1à3 c'est à dire respectivement l'état de santé, l'état psychologique et la satisfaction dans les rapports sociaux déclarés et un petit peu à la fréquence de consommation d'alcool et au salaire. La seconde dimension est davantage liée à la fréquence de consommation d'alcool (générique et binge drinking), au revenu et à la classe sociale.

On sait que l'axe 1 permet de distinguer selon les modalités des variables wb_1à3 mais on a besoin de savoir si le fait d'être sur la droite de l'axe 1 correspond à des modalités extrêmes faibles ou fortes des wb_1à3, autrement dit si un individu à droite se sentira plutôt "very good" socialement, physiquement et psychologiquement ou "very bad". Pour cela, on trace quand même le graphe des modalités (en brouillon).

In [69]:
dtn.plot_modalites_acm_simple(df_acm,mca_fr, actives, "France")
No description has been provided for this image

On voit que les modalités 6 des variables wb_1à3 sont largement les plus à droite, et les modalités 1 à 5 semblent triées plus ou moins dans l'ordre mais sont beaucoup plus proches des unes des autres. Or la modalité 6 correspond pour ces variables à " I prefer not to answer". L'axe 1 sépare donc en majorité les individus qui souhaitent répondre sur leur état de santé ou psychologique ou relationnel de ceux qui ne répondent pas. On remarque que l'axe 2 sépare les hauts salaires en haut des bas salaires en bas (puisque le 2ème quartile des revenus est le plus bas et les 3 et 4èmes plus hauts). Il sépare aussi mais de façon moins tranchée les fréquences de consommation occasionnelle (modalité la plus basse de f_1b) de la consommation régulière (plus en haut). L'axe 2 sépare aussi selon l'état de santé, psychologique et des relations sociales meilleur en haut et moins bon en bas. Les modalités sur le binge drinking (RSOD_2b) nous semblent trop proches pour être interprétées.

In [70]:
# Nuage des individus dans le plan des deux premiers axes de l'ACM
dtn.plot_individus_acm(mca_fr, df_acm, "France", actives)
No description has been provided for this image

Les individus isolés à droite de l'axe 1 sont des profils "atypiques", ils se distinguent non pas par leur mode de consommation, mais par leur refus de dévoiler leur état de santé ou psychologique ou de relations sociales. Cela participe sans doute à écraser le reste des données vers la gauche.

Voici l'interprétation de ton nuage des individus pour l'ACM France, basée sur les comportements que tu as identifiés (l'effet "non-réponse" sur l'axe 1 et le gradient socio-économique sur l'axe 2) :

La répartition en "peloton" par rapport à l'axe 2 permet (enfin) de cerner un tendance. Les individus situés dans la partie supérieure du nuage sont ceux qui cumulent les revenus les plus élevés (3ème et 4ème quartiles). Visuellement, on peut déduire que ce sont des profils plus "intégrés" socialement avec une consommation d'alcool régulière. L'aisance financière est corrélée à une consommation de routine et/ou sociale (car la fréquence de consommation d'alcool est plus haute et les répondants sont légèrement plus en haut à gauche vers les modalité plus "fair" "good", "very good" (respectivement 3,2,1) de l'état de vie social/sanitaire/psychologique). Inversement, les individus plus en bas du nuage principal représente la tendance d'une consommation d'alcool moins fréquente avec des revenus plus faibles.

Enfin, on distingue un petit nuage au Sud-Est du principal sans doute tiré par les abstinents d'après le nuage des modalités.

ACM Bulgarie¶

NB :L'ACP de la Bulgarie, de la Pologne et de l'Islande sont disponibles en annexe mais puisque les résultats sont très similaires à ceux de la France, eux même décevant, nous n'en faisons pas l'interprétation.

In [71]:
mca_bg = dtn.fait_acm(df_acm, "Bulgaria", actives)
dtn.plot_var_acm(mca_bg, "Bulgaria")
No description has been provided for this image

La première dimension explique 36% de la variance et la deuxième 33%, on se concentre sur ces deux là pour simplifier l'analyse (même si la troisième en explique aussi beaucoup).

In [72]:
#graphe des contributions de chaque variables aux 2 premiers axes
dtn.tracer_graphe_liaisons(mca_bg, "Bulgarie")
No description has been provided for this image

Le premier axe est lié à beaucoup de variable mais pas très fortement, on retiendra qu'il est notamment bien représenté par la fréquence générique et de consommation excessive d'alcool (RSOD_2b et f_1b) et à la classe sociale, tandis que le second axe est surtout lié à la qualité de l'état psychologique (WB_2) et dans un second temps social et de santé (WB_1 et WB_3), voire à la fréquence de consommation d'alcool générique et binge de manière moins significative.

In [73]:
dtn.plot_modalites_acm_simple(df_acm,mca_bg, actives, "Bulgaria")
No description has been provided for this image

Le nuage des modalités nous montre que les tendances en haut à droite du graphe sont celles de la modalité 5 des variables WB_1à3 soit des "very bad" état psychologiques, de santé et de relation sociale. L'axe 1, comme l'axe 2 séparent donc les "very good" au centre, des "very bad" au Nord-Est pour ces variables. Comme pour la France, la tendance pour la consommation se lit au Sud-Est pour les abstinent mais sur un axe plus prononcé suivant la 4ème bissectrice (axe Sud-Est/ Nord-Ouest), où plus on est au Nord-Ouest, plus la fréquence de consommation est régulière et dans une moindre mesure, plus le binge drinking est aussi régulier. Sur l'axe 1, la distribution des modalités pour les classes sociales est moins prononcée même si les "cols blancs" (social_class_2) et les "business person"(social_class_4) sont plus à gauche et les non répondnats et "other" (social_class_5 et 9) sont plus à droite. Les modalités des revenus représentent des revenus plus élevés à gauche qu'à droite de l'axe 1.

In [74]:
# Nuage des individus dans le plan des deux premiers axes de l'ACM
dtn.plot_individus_acm(mca_bg, df_acm, "Bulgaria", actives)
No description has been provided for this image

Le nuage des individus forme une masse centrale de points répartis de façon assez homogène, cela indique que les variables utilisées pour l'analyse ne parviennent pas à structurer des groupes d'individus distincts.

On observe bien une trainée d'individus rares vers le Nord-Est qui sont typiques des individus ayant un mauvais état de santé général ou psychologique ou de relation social. Cependant comme WB_1à3 sont bien représentés sur les 2 premiers axes il est difficile de dire si ces individus sont aussi tirés vers cette direction par d'autres variables et notamment la consommation d'alcool.

Comme pour la France, on observe une autre trainée d'individu vers le Sud-Est représentatifs des profils abstinent qui sont sans doute tiré vers la droite par leur mauvais état de santé ou de qualité relationnelle.

Finalement, la forme du nuage suggère que les liens entre santé, revenus/classe sociale et alcool sont plus hétérogènes en Bulgarie qu'en France. De plus, la mauvaise santé ou la mauvaise qualité des relations sociales semblent être des facteurs de différenciations beaucoup plus puissant chez les Bulgares que chez les Français.

ACM Islande¶

In [75]:
mca_ic = dtn.fait_acm(df_acm, "Iceland", actives)
dtn.plot_var_acm(mca_ic, "Iceland")
No description has been provided for this image

Comme avant, on se concentre sur les deux premières dimensions.

In [76]:
#graphe des contributions de chaque variables aux 2 premiers axes
dtn.tracer_graphe_liaisons(mca_ic, "Iceland")
No description has been provided for this image

Les WB_1à3 sont toujours les variables les plus liées au premier axe, suivies par la classe sociale et le niveau d'éducation (SD_9). Ce qui change c'est que RSOD_2b et f_1b, la fréquence de binge drinking et de consommation d'alcool sont très liées au second axe et qu'aucune autre variable n'y est vraiment liée.

In [77]:
dtn.plot_modalites_acm_simple(df_acm,mca_ic, actives, "Iceland")
No description has been provided for this image

Les modalités de fréquence de consommation d'alcool se répartissent de bas (les abstinents) en haut( les consommateurs quotidiens). Les modalités de fréquence de binge drinking sont moins ordonnées (binge rare en dessous de binge jamais mais aussi en dessous de binge intensif et régulier). On peut donc penser que le Binge drinking n'est pas vraiment caractéristique d'un type de consommateur d'alcool en terme de fréquence générique (puisque les deux sont très liés à l'axe 2 et que la fréquence est, elle, ordonnée).

Les niveaux d'éducations sont aussi répartis aussi d'une manière non ordonnée (difficilement interprétable). Les mauvais états de santé, de psychologie et de relation social sont généralement plus à droite et les bons plus à gauche.

In [78]:
# Nuage des individus dans le plan des deux premiers axes de l'ACM
dtn.plot_individus_acm(mca_ic, df_acm, "Iceland", actives)
No description has been provided for this image

Rappel: L'axe horizontal sépare les individus selon leur qualité de vie déclarée. L'axe vertical les sépares selon leur rapport à l'alcool.

La forme applatie et horizontale du nuage principol semble indiquer que peu importe le ressenti en terme d'état de santé/psychologique ou de relation social, tant qu'il reste dans des proportions raisonnables, la consommation des islandais est relativement similaire. Un second nuage, plus petit et translaté vers le haut semble indiquer qu'une part des islandais interrogés consomment un peu plus d'alcool que la population générale mais garde le même profil.

Cette ACM nous permet de dire que la consommation d'alcool des islandais ne varie que peu en fonction des caractéristiques socio-économiques et psychologiques.

ACM Pologne¶

In [79]:
mca_pl = dtn.fait_acm(df_acm, "Poland", actives)
dtn.plot_var_acm(mca_pl, "Poland")
No description has been provided for this image

Comme avant, on se concentre sur les deux premières dimensions.

In [80]:
#graphe des contributions de chaque variables aux 2 premiers axes
dtn.tracer_graphe_liaisons(mca_pl, "Poland")
No description has been provided for this image

L'axe 1 est lié à de nombreuses variables mais pas très fortement: l'état de santé/ psychologique et social, le revenu, le binge drinking et la fréquence de consommation d'alcool. L'axe 2 est plutôt lié à l'état de santé/ psychologique et social et très peu aux autres variables.

In [81]:
dtn.plot_modalites_acm_simple(df_acm,mca_pl, actives, "Poland")
No description has been provided for this image

Les modalités sont toutes très ramassées sans doute dû à l'écrasement induis par les non répondants aux variables WB_1à3 (code 6). Dans le prochain plot, on recentre donc le nuage des modalités sur le centre pour mieus les visualiser.

In [82]:
dtn.plot_modalites_acm_simple(df_acm,mca_pl, actives, "Poland", xlim=(-1, 1.5), ylim=(-1, 1.5))
No description has been provided for this image

On voit que sur l'axe Nord-Ouest / Sud-Est, les nivaux de salaires, la fréquence de consommation d'alcool et de Binge drinking et l'état de santé/ psychologique et d'épanouissement social est croissant en allant vers le Nord-Est. (La tendance pour les classes sociales n'est pas nette, on ne l'interpetera pas).

In [83]:
# Nuage des individus dans le plan des deux premiers axes de l'ACM
dtn.plot_individus_acm(mca_pl, df_acm, "Poland", actives)
No description has been provided for this image

Le nuage polonais se distingue par une forte cohérence interne : les dimensions économique, sanitaire et comportementale convergent vers une seule diagonale très dense.

Le profil type du consommateur polonais régulier (au Nord-Ouest) est celui d'un individu aisé et en bonne santé, tandis que les plus basses consommations (au Sud-Est) sont statistiquement associée à des indicateurs de bien-être et de revenus plus faibles. Il faut cependant s'interroger, comme pour la France, sur le rôle des non répondants aux variables WB_1à3 qui, comme vue sur le nuage des modalités, participent sans doute à créer une forme plus condensée et linéaire et à surinterpréter la cohérence des profils.

 

Partie III : Modélisation¶

Méthodologique : Sélection des Variables Significatives¶

Afin d'identifier les déterminants spécifiques de la consommation d'alcool pour chaque pays, nous avons adopté une méthodologie de régression linéaire multiple avec une procédure de sélection de variables par élimination descendante (Backward Elimination).

Pour chaque pays, la procédure s'initialise par l'ajustement d'un modèle saturé incluant l'ensemble des variables explicatives potentielles. À chaque itération, la significativité statistique de chaque co-variable est évaluée via le test de Student. La variable présentant la p-value la plus élevée supérieure au seuil critique fixé à $\alpha = 0.05$ (et modifiable par argument d'une fonction) est retirée du modèle.Ce dernier est ensuite réajusté sur les variables restantes.

Ce processus itératif est répété jusqu'à convergence, c'est-à-dire jusqu'à l'obtention d'un modèle final où tous les coefficients conservés sont statistiquement significatifs. Cette approche permet d'isoler les facteurs de risque propres à chaque contexte national.

In [84]:
variables_explicatives= [
    'SD_1',  # Genre
    'SD_2',  # Age
    'SD_4',  # Statut marital
    'SD_6',  # Taille ménage
    'SD_7',  # Mineurs
    'SD_8',  # Urbanisation
    'SD_9',  # Education
    'SD_10', # Activité pro
    "sd_20month_EUR_2020", # Revenu 
    "social_class", # Classe sociale
    "CH_1",  # Histoire familiale alcool
    "WB_1",  # Santé physique
    "WB_2",  # Santé mentale
    "WB_3"   # Satisfaction relationnelle
]
resultat = rgp.regression_iterative(
    df=data, 
    target_col='bsqf_alc', 
    all_feature_cols=variables_explicatives, 
    country_col='COUNTRY', 
    liste_pays=['France', 'Poland', 'Bulgaria', 'Iceland'],
    seuil_pvalue=0.05)
Démarrage de la sélection Stepwise pour 4 pays...  Pays : coef (p_value) 

Variable France Poland Bulgaria Iceland
const 1730.29 (0.000) 3220.98 (0.015) 25318.67 (0.000) -64.86 (0.460)
SD_1 -299.61 (0.000) -2313.62 (0.001) - -
SD_7 113.98 (0.004) 1375.59 (0.000) - -
social_class -35.98 (0.003) - - -
CH_1 -359.23 (0.000) - - -
SD_8 - 602.35 (0.025) - 37.26 (0.031)
SD_4 - - -1296.28 (0.023) 45.35 (0.001)
SD_6 - - -4660.17 (0.018) -
SD_9 - - -2397.77 (0.038) -42.52 (0.013)
WB_1 - - - 64.08 (0.001)
WB_2 - - - 94.63 (0.000)
R-carre 0.035 0.017 0.004 0.067

Rapport d'Analyse des Déterminants de la Consommation d'Alcool (Approche Prudente)¶

1. Préambule Méthodologique¶

Les modèles de régression linéaire ci-dessous présentent des coefficients de détermination () faibles, variant de 0,4 % (Bulgarie) à 6,7 % (Islande).

  • Signification : Les variables socio-démographiques et de bien-être expliquent une part très marginale de la variance de la consommation totale. La consommation d'alcool est donc un comportement très hétérogène, influencé par des facteurs non observés ici (habitudes culturelles, prix, génétique, contexte social immédiat).
  • Portée : L'échantillon n'étant pas statistiquement représentatif des populations nationales, les résultats suivants décrivent des corrélations internes à la base de données et ne doivent pas être généralisés sans réserve à l'ensemble de ces pays.

2. Analyse Détaillée¶

Bilan Global de la Modélisation¶

L'analyse des résultats issus de la sélection stepwise mets en évidence deux constats pour l'interprétation :

  • Un pouvoir explicatif marginal ($R^2$) : Les coefficients de détermination sont compris entre 0,004 (Bulgarie) et 0,067 (Islande). nous observons que les variables socio-démographiques et de bien-être expliquent une part très faible de la variance (moins de 7 % dans le meilleur des cas, et moins de 1 % pour la Bulgarie). Cela signifie que la consommation volumique d'alcool est un comportement complexe, qui échappe en grande partie aux déterminants sociologiques classiques (âge, sexe, situation familiale).
  • L'absence du revenu : La variable financière sd_20month_EUR_2020 (Revenu du ménage) a été éliminée par l'algorithme pour l'ensemble des pays, ne franchissant pas le seuil de significativité. Cela veut dire que le niveau de richesse pure n'est pas un prédicteur direct du volume d'alcool consommé.

France¶

Au sein de l'échantillon français, la consommation semble structurée par des déterminants "classiques" et une variable historique forte.

  • Genre (SD_1) : Avec un coefficient négatif significatif (-301,71), cela signifie que les hommes consommes significativement plus d'alcool que les femmes dans ce groupe.
  • Hérédité sociale (CH_1) : C'est une spécificité marquante des répondants français. La variable "Avoir vécu enfant avec un buveur excessif" (1=Oui, 2=Non) a un coefficient négatif (-360,84). Cela indique que les répondants n'ayant pas été exposés à l'alcoolisme familial durant l'enfance consomment significativement moins aujourd'hui.
  • Classe sociale (social_class) : Le coefficient négatif (-34,84) suggère un effet protecteur du statut social : à mesure que l'on s'élève dans la catégorie (de ouvrier vers cadre), le volume déclaré tend à diminuer légèrement.

Pologne¶

Les répondants polonais présentent des écarts de consommation très brutaux en fonction de leur environnement.

  • Genre (SD_1) : L'effet du genre est massif (-2327,88), bien plus fort qu'en France. Dans cet échantillon, la consommation déclarée est très majoritairement masculine.

  • Urbanisation (SD_8) : Le coefficient positif (+1389,14) indique une corrélation entre la taille de la ville et la consommation. Les répondants des grandes agglomérations déclarent boire davantage que ceux des zones rurales.

  • Structure familiale (SD_7) : La présence de mineurs au foyer est associée positivement à la consommation (+1389,14). Ce résultat contre-intuitif (on s'attendrait à ce que les parents boivent moins) pourrait refléter dans cet échantillon spécifique une consommation domestique plus ancrée ou un profil de répondants plus âgés/installés qui consomment davantage que les jeunes adultes sans enfants.

Bulgarie¶

Le modèle est extrêmement faible, ce qui indique que pour les répondants bulgares, les variables classiques (âge, sexe) ne prédisent rien. Seule la structure du foyer joue un rôle.

  • Isolement (SD_6) : Le coefficient très négatif (-4660,17) sur la variable "Taille du ménage" (1=Seul, 2=Plusieurs) est crucial. Il indique que le passage de la vie en solo à la vie en groupe fait chuter la consommation. Dans cet échantillon, les personnes vivant seules sont celles qui déclarent les plus gros volumes.
  • Statut marital (SD_4) : Le coefficient négatif (-1296,28) montre que les mariés (code 1) consomment plus que les autres statuts (codes élevés). Cela dessine une dichotomie chez les répondants bulgares : une consommation forte chez les isolés, mais aussi une consommation importante chez les couples mariés traditionnels.
  • Éducation (SD_9) : L'éducation agit comme un frein (-2397,77) : les répondants les plus diplômés déclarent des volumes plus faibles.

🇮🇸 Islande : Le lien Santé-Consommation ()¶

L'échantillon islandais est le mieux expliqué par le modèle, grâce à l'introduction des variables de santé.

  • Le Mal-être (WB_1, WB_2) : Les coefficients sont positifs. Puisque les échelles de santé vont de 1 (Très bon) à 5 (Très mauvais), un coefficient positif signifie que plus la santé physique et mentale déclarée est mauvaise, plus la consommation d'alcool est élevée. L'alcool apparaît ici corrélé au mal-être.

  • Statut Marital (SD_4) : Contrairement à la Bulgarie, le coefficient positif (+45,35) indique ici que ce sont les personnes seules, divorcées ou veuves (codes élevés) qui consomment plus que les personnes mariées (code 1).

Éducation (SD_9) : Comme en Bulgarie, un niveau d'éducation élevé est associé à une consommation moindre (-42,52).

3. Synthèse Comparative¶

L'analyse de ces données non-représentatives permet néanmoins de dégager quatre profils de corrélation distincts au sein de l'étude :

  1. Le profil socio-culturel (France) : Où la consommation est liée au genre et à l'histoire familiale.
  2. Le profil environnemental (Pologne) : Où le lieu de vie (ville) et la composition du foyer (enfants) sont déterminants.
  3. Le profil "Solitaire" (Bulgarie) : Où vivre seul est le facteur de risque statistique le plus fort identifié.
  4. Le profil "Symptomatique" (Islande) : Où la consommation est significativement corrélée à une mauvaise auto-évaluation de la santé physique et mentale.

Note de prudence finale : Ces résultats soulignent des associations statistiques au sein des répondants enquêtés. Ils ne permettent pas d'établir de causalité directe ni de décrire les habitudes de la population générale de ces pays.

Annexes¶

Annexes Partie de la partie II

In [85]:
print("matrice des corrélations ACP France")
matrice_fr = dtn.obtenir_matrice_pca(data, "France", quanti.columns)
matrice_fr
matrice des corrélations ACP France
Out[85]:
SD_2 SD_7 sd_20month_EUR_2020 bsqf_alc cbsqf_beer cbsqf_spir cbsqf_wine
SD_2 1.000596 -0.202580 0.127745 -0.043799 -0.081333 -0.058563 0.062788
SD_7 -0.202580 1.000596 0.058183 0.083295 0.086820 0.052204 0.043114
sd_20month_EUR_2020 0.127745 0.058183 1.000596 0.020459 0.008664 -0.000607 0.029069
bsqf_alc -0.043799 0.083295 0.020459 1.000596 0.881673 0.700625 0.667198
cbsqf_beer -0.081333 0.086820 0.008664 0.881673 1.000596 0.463107 0.387182
cbsqf_spir -0.058563 0.052204 -0.000607 0.700625 0.463107 1.000596 0.342601
cbsqf_wine 0.062788 0.043114 0.029069 0.667198 0.387182 0.342601 1.000596
In [86]:
print("matrice des corrélations ACP Bulgarie")
matrice_bg = dtn.obtenir_matrice_pca(data, "Bulgaria", quanti.columns)
matrice_bg
matrice des corrélations ACP Bulgarie
Out[86]:
SD_2 SD_7 sd_20month_EUR_2020 bsqf_alc cbsqf_beer cbsqf_spir cbsqf_wine
SD_2 1.000334 -0.143752 0.032778 -0.013679 -0.004385 0.063876 -0.012236
SD_7 -0.143752 1.000334 -0.014369 0.019948 0.028491 -0.014644 -0.007708
sd_20month_EUR_2020 0.032778 -0.014369 1.000334 -0.015067 0.040315 0.016704 0.007130
bsqf_alc -0.013679 0.019948 -0.015067 1.000334 0.185589 0.059917 0.064783
cbsqf_beer -0.004385 0.028491 0.040315 0.185589 1.000334 0.252698 0.238649
cbsqf_spir 0.063876 -0.014644 0.016704 0.059917 0.252698 1.000334 0.165742
cbsqf_wine -0.012236 -0.007708 0.007130 0.064783 0.238649 0.165742 1.000334
In [87]:
# On calcule l'ACP sur les quanti.colums/ variables quantitatives
pca_bg, feat_bg, cols_bg = dtn.calculer_acp_pays(data, "Bulgaria", quanti.columns)

# Et on trace
if pca_bg is not None:
    dtn.trace_cercle_et_variance(pca_bg, cols_bg, "Bulgaria")
No description has been provided for this image
In [88]:
print("matrice des corrélations ACP Pologne")
matrice_Pl = dtn.obtenir_matrice_pca(data, "Poland", quanti.columns)
matrice_Pl
matrice des corrélations ACP Pologne
Out[88]:
SD_2 SD_7 sd_20month_EUR_2020 bsqf_alc cbsqf_beer cbsqf_spir cbsqf_wine
SD_2 1.000642 -0.186116 0.011105 -0.007241 0.013528 -0.004672 -0.048204
SD_7 -0.186116 1.000642 0.111931 0.083747 0.077937 0.081090 0.109368
sd_20month_EUR_2020 0.011105 0.111931 1.000642 0.023920 0.046927 0.041686 0.044042
bsqf_alc -0.007241 0.083747 0.023920 1.000642 0.115154 0.194679 0.133516
cbsqf_beer 0.013528 0.077937 0.046927 0.115154 1.000642 0.414116 0.449896
cbsqf_spir -0.004672 0.081090 0.041686 0.194679 0.414116 1.000642 0.430644
cbsqf_wine -0.048204 0.109368 0.044042 0.133516 0.449896 0.430644 1.000642
In [89]:
# On calcule l'ACP sur les quanti.colums/ variables quantitatives
pca_pl, feat_pl, cols_pl = dtn.calculer_acp_pays(data, "Poland", quanti.columns)

# Et on trace
if pca_fr is not None:
    dtn.trace_cercle_et_variance(pca_fr, cols_fr, "Poland")
No description has been provided for this image
In [90]:
print("matrice des corrélations ACP Islande")
matrice_Ic = dtn.obtenir_matrice_pca(data, "Iceland", quanti.columns)
matrice_Ic
matrice des corrélations ACP Islande
Out[90]:
SD_2 SD_7 sd_20month_EUR_2020 bsqf_alc cbsqf_beer cbsqf_spir cbsqf_wine
SD_2 1.000693 -0.068888 0.062011 -0.017617 -0.043122 -0.034362 0.056520
SD_7 -0.068888 1.000693 0.023438 0.012568 -0.016451 0.031155 0.028939
sd_20month_EUR_2020 0.062011 0.023438 1.000693 -0.011649 -0.045335 -0.014624 0.023352
bsqf_alc -0.017617 0.012568 -0.011649 1.000693 0.783077 0.589530 0.546695
cbsqf_beer -0.043122 -0.016451 -0.045335 0.783077 1.000693 0.241610 0.122356
cbsqf_spir -0.034362 0.031155 -0.014624 0.589530 0.241610 1.000693 0.099296
cbsqf_wine 0.056520 0.028939 0.023352 0.546695 0.122356 0.099296 1.000693
In [91]:
# On calcule l'ACP sur les quanti.colums/ variables quantitatives
pca_ic, feat_ic, cols_ic = dtn.calculer_acp_pays(data, "Iceland", quanti.columns)

# Et on trace
if pca_ic is not None:
    dtn.trace_cercle_et_variance(pca_ic, cols_ic, "Iceland")
No description has been provided for this image